leetcode 234回文链表

方法一:存数组双指针

cpp 复制代码
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        vector<int> vals;
        while (head != nullptr) {
            vals.emplace_back(head->val);
            head = head->next;
        }
        for (int i = 0, j = (int)vals.size() - 1; i < j; ++i, --j) {
            if (vals[i] != vals[j]) {
                return false;
            }
        }
        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:
    bool isPalindrome(ListNode* head) {
        if(head==nullptr){
            return true;
        }
        ListNode *firsthalfend = middlenode(head);//找中点
        ListNode *secondnode = reverselist(firsthalfend->next); //反转链表 找末尾点

        ListNode *p1 = head;
        ListNode *p2 = secondnode;
        while(p2!=nullptr){
            if(p1->val !=p2->val){
                return false;
            }
            p1 = p1->next;
            p2 = p2->next;
        }
        return true;
    }
        ListNode *middlenode(ListNode *head){
            ListNode *slow = head;
            ListNode *fast = head;
            while(fast->next!=nullptr && fast->next->next!=nullptr){
                slow = slow->next;
                fast = fast->next->next;
            }
            return slow;
        }

        ListNode *reverselist(ListNode *head){
            ListNode *pre = nullptr;
            ListNode *cur = head;
            while(cur!=nullptr){
                ListNode *next = cur->next;
                cur->next = pre;
                pre = cur;
                cur = next;
            }
            return pre;
        }
};

这段代码的核心思路可以精简成一句话:

先用快慢指针找到前半部分的末尾,再反转后半部分,最后让前后两部分同时向后遍历比较。

具体过程是:middlenode(head) 用快慢指针找中点,slow 每次走一步,fast 每次走两步,因此当 fast 到链表尾部时,slow 位于前半部分末尾。然后通过

复制代码
reverselist(firsthalfend->next)

把后半部分链表反转。比如:

复制代码
1 -> 2 -> 2 -> 1

变成比较:

1 -> 2
1 -> 2

之后:

复制代码
p1 = head;
p2 = secondnode;

两个指针同时向后走,只要出现:

复制代码
p1->val != p2->val

就说明不是回文,返回 false;如果 p2 全部遍历结束都相等,就返回 true

你可以把整题记成:

复制代码
找中点
  ↓
反转后半部分
  ↓
前后两部分逐个比较
  ↓
全部相等 → true
出现不同 → false

易错点

1. 找中点时要判断 fast,不是 slow

正确:

复制代码
while (fast->next != nullptr &&
       fast->next->next != nullptr)

因为 fast 一次走两步,必须提前保证它后面有节点,否则容易出现:

复制代码
nullptr->next

导致空指针错误。

2. 反转链表循环条件要写 cur != nullptr

复制代码
while(cur != nullptr)

因为真正不断移动的是:

复制代码
cur = next;

如果误写成:

复制代码
while(head != nullptr)

由于 head 没有变化,很可能导致死循环。

3. 反转链表一定要先保存下一个节点。

复制代码
ListNode* next = cur->next;
cur->next = pre;

不能先反转再找 cur->next,否则原来的后续链表会丢失。

所以顺序一定是:

复制代码
保存 next
↓
反转箭头
↓
pre 前进
↓
cur 前进

4. 后半部分从 firsthalfend->next 开始。

正确:

复制代码
reverselist(firsthalfend->next)

不是:

复制代码
reverselist(firsthalfend)

否则会把中间节点也一起反转,容易把链表结构弄乱。

5. 比较循环看 p2 是否结束。

复制代码
while(p2 != nullptr)

因为我们只需要比较后半部分的长度。对于奇数长度链表,中间节点不需要参与比较。

例如:

复制代码
1 -> 2 -> 3 -> 2 -> 1

只需要比较:

复制代码
1 -> 2
1 -> 2

中间的 3 不影响回文判断。

6. bool 函数最后别忘了 return true;

复制代码
return true;

否则所有节点都比较成功之后,函数没有返回值,会出现:

复制代码
non-void function does not return a value

最后可以把这题压缩成一个记忆口诀:

快慢找中点,后半做反转;双指针比较,不同就返回。

时间复杂度是 O(n) ,额外空间复杂度是 O(1)

相关推荐
Super 含1 小时前
Android 启动优化(三):Perfetto 实战——启动时间到底花在哪里?
jvm·算法
地平线开发者2 小时前
征程6|YOLOv5x 在 Horizon J6 平台的完整部署实战(上)
算法
青 春 记 忆2 小时前
LeetCode 104. 二叉树的最大深度|Python 解法详解
python·算法·leetcode
watersink2 小时前
机器学习关联分析
人工智能·算法·机器学习
牛油果子哥q2 小时前
C++STL算法超全精讲:排序/查找/去重/遍历/最值/合并全套API、仿函数、Lambda适配、实战避坑
开发语言·c++·算法
AI服务老曹2 小时前
摄像机安装AI视频分析完整流程:从现场物理安装、硬解配置到算法POC效果验证
人工智能·算法·音视频
孤存5222 小时前
c语言动态内存管理
c语言·开发语言·算法
牛阿大2 小时前
MPC算法
算法
薛定e的猫咪2 小时前
(ICLR2025) C‑MORL :基于约束优化高效挖掘 MORL 帕累托前沿
人工智能·深度学习·算法
祖力552 小时前
快速学会数据结构中的链式队列与循环队列
linux·c语言·数据结构·算法