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)。

相关推荐
東隅已逝,桑榆非晚9 小时前
算法6. 双指针法-查找总价格为目标的两个商品
c++·学习·算法
Eyfcom9 小时前
〖物联网终端实战 01〗UWB 室内高精度定位:仓储 AGV 与人员的厘米级轨迹追踪
物联网·算法·物流系统·快递系统·跨境物流快递系统·物联网终端实战
bro_Java66610 小时前
《排序的底层逻辑:比较、交换与分治》
java·算法·排序算法
爱喝雪碧的可乐10 小时前
MATLAB
开发语言·算法·matlab
叼烟扛炮11 小时前
Linux 学习笔记(六十):单线程的逆袭——epoll 高并发服务器实战
linux·服务器·网络·笔记·学习·算法
careathers11 小时前
【数据结构】基于比较的排序算法 - 交换排序
数据结构·算法·排序算法
文丑颜不良啊12 小时前
LeetCode2081~2100题目解析
java·leetcode
Rabitebla12 小时前
【Linux操作系统】进程篇(十一):进程程序替换——从底层原理到 exec 函数族
linux·服务器·c++·笔记·学习·算法
tellmewhoisi13 小时前
深度学习0:数学知识:正态分布1
人工智能·深度学习·算法
-梅13 小时前
算法(1) 动态规划
算法·动态规划