题目
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
示例 1:
输入: head = [1,2,2,1]
**输出:**true
示例 2:
输入: head = [1,2]
**输出:**false
法一(数组辅助+双指针):
题解
将链表中的数值复制到一个数组中,然后使用双指针从两端向中间比较即可
答案
cpp
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int> nums;
while(head!=NULL){
nums.push_back(head->val);
head=head->next;
}
int i=0,j=nums.size()-1;
while(i<j){
if(nums[i]==nums[j]){
i++;
j--;
}
else {
return false;
}
}
return true;
}
};
复杂度分析
-
时间复杂度 :O(n)
遍历链表一次 O(n),双指针遍历数组一次 O(n/2) ≈ O(n)。
-
空间复杂度 :O(n)
使用一个与链表长度相同的数组存储所有节点的值。
法二(快慢指针找中点+反转后半段链表):
题解
1.使用快慢指针找到链表的中间节点(前半部分的尾节点)。
- 定义快指针 fast 和慢指针 slow,都指向 head。
- 当 fast->next 和 fast->next->next 均不为空时,fast 每次移动两步,slow 每次移动一步。
- 循环结束时,slow 指向的就是前半部分的尾节点。
2.反转链表的后半部分(详见如下解析:题目LeetCode热题100------206.反转链表)
3.同时遍历前半部分和反转后的后半部分,比较对应节点的值是否相等。
4.恢复链表原状。
答案
cpp
class Solution {
public:
bool isPalindrome(ListNode* head) {
ListNode* firstHalfEnd = endOfFirstHalf(head);
ListNode* secondHalfStart = reverseList(firstHalfEnd->next);
ListNode* p1=head;
ListNode* p2=secondHalfStart;
while(p2!=NULL){
if(p1->val!=p2->val) return false;
p1=p1->next;
p2=p2->next;
}
//恢复链表
firstHalfEnd->next=reverseList(secondHalfStart);
return true;
}
//快慢指针找前半部分的尾节点
ListNode* endOfFirstHalf(ListNode* head){
ListNode* fast=head;
ListNode* slow=head;
while(fast->next!=NULL&&fast->next->next!=NULL){
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
//反转链表,返回后半部分的新头节点
ListNode*reverseList(ListNode* head){
ListNode* pre=NULL;
ListNode* cur=head;
while(cur!=NULL){
ListNode* nextTemp=cur->next;
cur->next=pre;
pre=cur;
cur=nextTemp;
}
return pre;
}
};
复杂度分析
-
时间复杂度 :O(n)
找中点 O(n),反转链表 O(n),比较 O(n),整体 O(n)。
-
空间复杂度 :O(1)
只使用了若干个指针变量,没有使用额外的数组或递归栈。