题目描述
请判断一个链表是否为回文链表。
示例:
输入: 1->2
输出: false
输入: 1->2
输出: false
题目链接:https://leetcode-cn.com/problems/palindrome-linked-list/
思路1
回文链表就是正向遍历序列和反向遍历序列一样的链表,所以可以遍历链表一边,用队列记录链表的正向遍历序列,用栈记录反向遍历序列,然后比较即可。下面的代码没有用队列,用的是vector,其实是一样的。代码如下:
/**
* 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;
}
vector<int> v; // 记录正向遍历序列
stack<int> s; // 记录反向遍历序列
while(head!=nullptr){
v.push_back(head->val);
s.push(head->val);
head = head->next;
}
for(int i=0; i<v.size(); i++){
int st = s.top();
s.pop();
if(v[i]!=st){
return false;
}
}
return true;
}
};
- 时间复杂度:O(n)
- 空间复杂度: O(n)
用到了vector和栈,辅助空间随着链表的增长而线性增长。
思路2
先将链表分为两部分,然后将第二部分(后一部分)翻转后与第一部分比较。
将链表分为两部分可以先求链表长度n,然后找第n/2个节点。因为链表的长度可能为偶数和奇数,这两种情况下的分割是不一样的。当链表长度为偶数时,两条链表长度相等;当长度为奇数时,第一条链表的长度比第二条链表的长度大一,所以要翻转第二条链表并根据第二条链表比较。代码如下:
/**
* 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 || head->next==nullptr){
return true;
}
/*分割链表*/
ListNode* slow = head;
ListNode* fast = head;
while(fast->next!=nullptr && fast->next->next!=nullptr){
fast = fast->next->next;
slow = slow->next;
}
ListNode* head1 = head;
ListNode* head2 = slow->next;
slow->next = nullptr;
/*翻转后一个链表*/
ListNode* curNode = head2;
ListNode* preNode = nullptr;
ListNode* nextNode = nullptr;
while(curNode!=nullptr){
nextNode = curNode->next;
curNode->next = preNode;
preNode = curNode;
curNode = nextNode;
}
head2 = preNode;
while(head2!=nullptr){ // 注意要使用第2个链表,因为第2个链表长度小于等于第1个链表长度
if(head1->val != head2->val){
return false;
}
head1 = head1->next;
head2 = head2->next;
}
return true;
}
};
- 时间复杂度: O(n)
- 空间复杂度: O(1)