题目链接
回文结构即字符串正序逆序完全一致,如“1 2 3 4 3 2 1”,那么我们就要想办法同时比较链表头和链表尾的元素,看其是否相等。
下面介绍一种最常用的方法:
如果我们仔细观察回文结构,就会得到一个结论:
将一个回文结构从正中间分隔,再将后半部分逆序,那么前半部分就一定等于后半部分。
我们可以分链表长度为奇数和偶数讨论:
当长度为偶数:
当长度为奇数:
定义两个指针fast、slow
,同时指向链表头,slow
每次走一个,fast
每次走两个节点,当fast->next == NULL 或者 fast == NULL
时,slow
就走到中间节点了
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
slow
节点为头的链表,如果对单链表反转还不太了解的朋友,建议先看看反转单链表struct ListNode* reverseList(struct ListNode* head)
{
if (head == NULL)
return NULL;
struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
newHead->next = head;
struct ListNode* cur = head;
while (cur->next)
{
struct ListNode* curNext = cur->next;
cur->next = curNext->next;
curNext->next = newHead->next;
newHead->next = curNext;
}
struct ListNode* retHead = newHead->next;
free(newHead);
return retHead;
}
mid
来接受slow
后链表反转过后的头,接下来,从原来链表的头和mid
开始比较,只要遇到不相等的情况,就返回false
,否则返回true
。struct ListNode* mid = reverseList(slow->next);
struct ListNode* cur1 = head;
struct ListNode* cur2 = mid;
while (cur1 && cur2)
{
if (cur1->val != cur2->val)
{
return false;
}
cur1 = cur1->next;
cur2 = cur2->next;
}
return true;
判断过后,链表的结构是这样的:
如果我们要将链表还原,那么问号处的节点的后面应该链接到reverseList(mid)
的返回值,但问题是之前我们并没有保存问号处的节点。所以,我们可以对找到链表中间节点这一操作进行改进:
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast->next && fast->next->next)
{
slow = slow->next;
fast = fast->next->next;
}
这样slow
就会停留在问号处的位置,反转链表的时候就反转以slow->next
为头的链表就行了
struct ListNode* reverseList(struct ListNode* head) //反转链表
{
if (head == NULL)
return NULL;
struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
newHead->next = head;
struct ListNode* cur = head;
while (cur->next)
{
struct ListNode* curNext = cur->next;
cur->next = curNext->next;
curNext->next = newHead->next;
newHead->next = curNext;
}
struct ListNode* retHead = newHead->next;
free(newHead);
return retHead;
}
bool isPalindrome(struct ListNode* head){
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast->next && fast->next->next) //找到中间节点的前一个节点
{
slow = slow->next;
fast = fast->next->next;
}
//反转以中间节点为头的链表
//将返回值赋给mid
struct ListNode* mid = reverseList(slow->next);
struct ListNode* cur1 = head;
struct ListNode* cur2 = mid;
bool ret = true; //设置返回值
while (cur1 && cur2)
{
if (cur1->val != cur2->val)
{
ret = false; //只要出现不相等的情况,就将返回值设为false,推出比较
break;
}
cur1 = cur1->next;
cur2 = cur2->next;
}
//还原链表
mid = reverseList(mid);
slow->next = mid;
//返回
return ret;
}