请判断一个链表是否为回文链表。
示例 1:
输入: 1->2 输出: false
示例 2:
输入: 1->2->2->1 输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
思路:
这是一道简单难度的题,看见判断回文,首先想到试着用栈来暂存前半部分字符然后与后半部分字符对比,数字相同则出栈,如果能够空栈则一定是偶数个节点的回文链表,如果剩一个则是奇数个节点的链表。似乎这样不必扫描多次链表,但这种做法根本无法分辨1->2->3->2->1和 3-> 1->2->2->1这两种情况,所以必须找到链表的中点在何处。而且这个思路同” 建立一个list,然后将链表中的数存进去,然后判断这个list是否回文 ” 以及建立Hash表检查是否存在的思路一样,无法无法满足O(1) 的空间复杂度。
因此采取“先找到中点然后反转后半部分链表,再从头部和中点开始扫描链表对比是否节点值相同”的思路。找到中点依靠快慢指针即可,快指针一次循环前进两个节点慢指针一次前进一个节点,这样当循环结束时,慢指针一定会停在中点节点(奇数个节点情形)或是前半部分的最后一个节点上(偶数个节点情形),可以依靠快指针指向节点的下一个节点是否存在来判断上述情形:如果快指针的下一个节点存在则说明共有偶数个节点,慢指针停在前半部分的最后一个节点上;如果快指针的下一个节点不存在,则说明共有奇数个节点,慢指针停在中点节点上。
至于反转链表,使用类似头插法的方式完成即可。不过要注意,慢指针指向的节点其next域总是指向已经反转的部分链表的最后一个节点,例如 1->2->3->4->3->2->1翻转后会变成 1->2->3->4->3<-2<-1 ,此时应注意一下循环的结束条件。
AC代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head)
{
if(head == nullptr)
return true;
ListNode* fastCursor = head;
ListNode* slowCursor = head;
while(fastCursor->next != nullptr && fastCursor->next->next != nullptr)
{
fastCursor = fastCursor->next->next;
slowCursor = slowCursor->next;
}
if(fastCursor->next != nullptr)
{
ListNode* ReversedHead = slowCursor->next;
slowCursor->next = nullptr;
ReversedHead = ReverseList(ReversedHead);
while(head != nullptr && ReversedHead != nullptr)
{
if(head->val != ReversedHead->val)
return false;
head = head->next;
ReversedHead = ReversedHead->next;
}
return true;
}
else
{
ListNode* ReversedHead = slowCursor->next;
ReversedHead = ReverseList(ReversedHead);
while(head != slowCursor && ReversedHead != nullptr)
{
if(head->val != ReversedHead->val)
return false;
head = head->next;
ReversedHead = ReversedHead->next;
}
return true;
}
}
ListNode* ReverseList(ListNode* head)
{
ListNode* cur = NULL;
while (head) {
ListNode* nextNode = head -> next;
head -> next = cur;
cur = head;
head = nextNode;
}
return cur;
}
};
Published by