原题链接:Leetcode 234. 回文链表

解法一:转换为数组
cpp
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int> val;
while(head!=nullptr){
val.push_back(head->val);
head=head->next;
}
int l=0,r=val.size()-1;
while(l<r){
if(val[l]!=val[r]){
return false;
}
l++;
r--;
}
return true;
}
};
解法二:
- 找到前半部分链表的尾节点。
- 反转后半部分链表。
- 判断是否回文。
cpp
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
// 876. 链表的中间结点
ListNode * middleNode(ListNode* head) {
ListNode* fast=head;
ListNode* slow=head;
while(fast!=nullptr && fast->next!=nullptr){
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
// 206. 反转链表
ListNode * reverseList(ListNode* head) {
ListNode* pre=nullptr;
ListNode* now=head;
while(now!=nullptr){
ListNode* tmp=now->next;
now->next=pre;
pre=now;
now=tmp;
}
return pre;
}
bool isPalindrome(ListNode* head) {
ListNode* middle = middleNode(head);
ListNode* head2 = reverseList(middle);
while(head2){
if(head->val!=head2->val) return false;
head=head->next;
head2=head2->next;
}
return true;
}
};
问:为什么不能反转整个链表,然后判断?
答: 代码中用的反转链表的做法是题目206. 反转链表的做法,是在原地修改链表的,而不是"复制后修改",也就是反转链表的操作会影响原来的链表,返回的头节点是原链表的尾节点
ListNode* copy = head;
ListNode* reversedCopy = reverseList(copy);
这样的做法是不行的,因为 ListNode* copy = head; 并没有真正复制链表,只是让 copy 指针和 head 指针指向同一个链表(内存地址相同)。此时对 copy 进行反转操作,本质上还是在修改原链表的节点,和直接反转 head 没有区别。(ListNode* copy = head; 是指针赋值,不是链表复制,copy 和 head 指向的是同一片内存(同一个链表节点序列)。)
举例说明: 原链表:1 -> 2 -> 3 -> null 执行 ListNode* copy = head; 后,copy 和 head都指向 1。 反转 copy 后,链表变成 1 <- 2 <- 3(copy 现在指向 3),但原链表的 head 仍然指向 1,而
1->next 已经变成 null------ 原链表被破坏了。
要真正避免影响原链表,必须为每个节点创建新的副本(用 new ListNode(...)),而不是简单地复制指针。如:
cpp
//复制链表(创建新节点,不影响原链表)
ListNode* copyList(ListNode* head) {
if (head == nullptr) return nullptr;
// 创建虚拟头节点简化复制
ListNode* dummy = new ListNode(0);
ListNode* curr = dummy;
while (head != nullptr) {
// 为每个节点创建副本
curr->next = new ListNode(head->val);
curr = curr->next;
head = head->next;
}
return dummy->next;
}