前言:内容包括-题目,代码实现,大致思路,代码解读
题目:
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
示例 1:
输入:head = [1,2,2,1]
输出:true
示例 2:
输入:head = [1,2]
输出:false
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/palindrome-linked-list
代码实现:
//找中间结点
struct ListNode*FindMid(struct ListNode*head)
{
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
//翻转后半段链表
struct ListNode* reverse(struct ListNode*head)
{
struct ListNode* prev = NULL;
struct ListNode* cur = head;
while (cur)
{
struct ListNode* next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
if (next)
{
next = next->next;
}
}
return prev;
}
bool isPalindrome(struct ListNode* head)
{
struct ListNode* mid = FindMid(head);
struct ListNode* rmid = reverse(mid);
while (rmid)
{
if (head->val == rmid->val)
{
head = head->next;
rmid = rmid->next;
}
else
{
return false;
}
}
return true;
}
大致思路:
1 翻转后半段链表:
a 找到中间结点
b 翻转中间结点(包括中间结点在内)后面的所有结点
2 比较前半段链表和翻转后的后半段链表:
a 若是前半段中的结点值==后半段中的结点值 继续走向下一对要比较的结点
b 若是前半段中的结点值!=后半段中的结点值,表示该链表非回文链表
比如:原链表 1 2 2 1
翻转后半段: 1 2 1 2
前半段 1 2和后半段 1 2 完全相同,表示该链表是回文链表
代码解读:
part 1 找寻中间结点的函数 FindMid
struct ListNode*FindMid(struct ListNode*head)
{
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
快慢指针法:slow一次走一步,fast一次走两步
当fast为NULL(结点个数为偶数个)或者fast->next为NULL(结点个数为奇数个)时循环结束,slow就是中间结点。
偶数个结点的链表它的中间结点有两个,我们取较后的一个为最终正确的中间结点
part 2 翻转后半段链表
struct ListNode* reverse(struct ListNode*head)
{
struct ListNode* prev = NULL;
struct ListNode* cur = head;
while (cur)
{
struct ListNode* next = cur->next;
cur->next = prev;//改变结点next的指向
//下面是迭代
prev = cur;
cur = next;
if (next)//next若已经是NULL,则不执行下面这行代码,否则就是对NULL指针解引用
{
next = next->next;
}
}
return prev;//prev就是翻转后的链表的头结点
}
part 3
bool isPalindrome(struct ListNode* head)
{
struct ListNode* mid = FindMid(head);
struct ListNode* rmid = reverse(mid);
while (rmid)
{
if (head->val == rmid->val)
{
head = head->next;
rmid = rmid->next;
}
else
{
return false;
}
}
return true;
}
遍历比较前半段链表和翻转后的后半段链表
结点的值相同则继续比较下一对
结点的值不同则返回false