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)

相关推荐
a1879272183141 分钟前
【算法】动态规划第四篇:背包收官——min 哨兵、计数世界与组合排列分水岭
算法·leetcode·动态规划·dp·01背包·算法讲解·决策合并
2601_962297481 小时前
在python3中、下列输出变量a的正确写法是_2020超星大数据Python免费答案
数据结构·python·算法·编程·字符串操作
辰烨chenye1 小时前
LeetCode Hot 100 题解 · 子串篇
算法·leetcode·职场和发展
辰烨chenye1 小时前
LeetCode Hot 100 题解 · 堆篇
java·算法·leetcode
手写码匠2 小时前
华为云Flexus+DeepSeek征文|DeepSeek 应用监控告警体系实战:从“用户投诉才知道“到“故障前就发现“
人工智能·深度学习·算法·aigc
shehuiyuelaiyuehao2 小时前
算法29,前缀和,除自身以外的数组的乘积
java·数据结构·算法
智购科技自动售货机厂家2 小时前
2026自动售货机设备清洁效果自动验证:从图像比对到评分算法的工程实践~YH
人工智能·算法·计算机视觉
姜穆澜3 小时前
机器学习实战指南:从算法原理到工程落地
人工智能·算法·机器学习
啵啵啵鱼3 小时前
DS-顺序表
java·数据结构·笔记·后端·链表·obsidian