LeetCode-234. 回文链表
题目描述
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
思路
数组加双指针
首先给出一个比较简单明了的思路,双指针。还记得用双指针的方法来判断回文字符串,但是单链表无法反向进行索引,需要先将单链表转换成数组再进行判断。
bool isPalindrome(ListNode* head) {
vector<int> listVal;
while(head)
{
listVal.push_back(head->val);
head = head->next;
}
int iPre = 0;
int iEnd = listVal.size() - 1;
while(iPre < iEnd)
{
if(listVal[iPre] != listVal[iEnd])
return false;
iPre++;
iEnd--;
}
return true;
}
反转单链表解法
找到单链表的中间结点。
- 链表长度为奇数(2n+1)时索引为n。
如1->2->3->2->1, 则中间结点为3. - 链表长度为偶数2n时为n-1。
如1->2->3->3->2->1, 则中间结点为第一个3.
将中间结点之后的一半链表进行反转。
反转之后只需要进行一次扫描就可以得出结论。
如1->2->3->2->1经过反转之后变为1->2->3->1->2。
1->2->3->3->2->1经过反转之后变为1->2->3->3->2->1。
接下来要解决的两个问题就是如何找到链表的中间的结点和如何反转链表。
链表中间结点的确定可以采取快慢指针的方法,快指针每次循环前进两步,慢指针每次循环前进一步,当快指针到达链表的结尾时,慢指针指向的结点恰好是链表的中间结点。
ListNode *fast = head;
ListNode *slow = head;
while(fast->next != NULL && fast->next->next!= NULL)
{
fast = fast->next->next;
slow = slow->next;
}
反转单链表仍然可以采用双指针的方法。
ListNode* reverseList(ListNode *head)
{
ListNode *pre = NULL;
ListNode *next = NULL;
while(head != NULL)
{
next = head->next;
head->next = pre;
pre = head;
head = next;
}
return pre;
}
以链表1->2->3->4->5为例简单分析下上述代码的反转过程。
1 2->3->4->5
1<-2 3->4->5
1<-2<-3 4->5
1<-2<-3<-4 5
1<-2<-3<-4<-5
最终解法。
bool isPalindromePro(ListNode* head)
{
if(head == NULL || head->next == NULL)
return true;
ListNode *fast = head;
ListNode *slow = head;
while(fast->next != NULL && fast->next->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
}
slow->next = reverseList(slow->next);
slow = slow->next;
while(slow != NULL)
{
if(head->val != slow->val)
return false;
head = head->next;
slow = slow->next;
}
return true;
}
ListNode* reverseList(ListNode *head)
{
ListNode *pre = NULL;
ListNode *next = NULL;
while(head != NULL)
{
next = head->next;
head->next = pre;
pre = head;
head = next;
}
return pre;
}