DAILY DOCDAILY DOC
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
  • Array

    • 数组
    • 二分查找
    • moveZeros
  • Dynamic-programming

    • 动态规划
  • 刷题指南
  • String

    • 字符串
  • bitwise-operator

    • 位运算符
  • heap
  • history

    • [1014] 最佳观光组合
    • [1022] 从根到叶的二进制数之和
    • [104] 二叉树的最大深度
    • [11] 盛最多水的容器
    • [110] 平衡二叉树
    • [1227] 飞机座位分配概率
    • [129] 求根节点到叶节点数字之和
    • [1306] 跳跃游戏 III
    • [148] 排序链表
    • 155.最小栈
    • [165] 比较版本号
    • 1763. 最长的美好子字符串
    • [1870] 准时到达的列车最小时速
    • [199] 二叉树的右视图
    • [21] 合并两个有序链表
    • 215.数组中的第 k 个最大元素
    • [2306] 公司命名
    • [234] 回文链表
    • [2516] 每种字符至少取 K 个
    • [316] 去除重复字母
    • [3171] 找到按位或最接近 K 的子数组
    • [322] 零钱兑换
    • [41] 缺失的第一个正数
    • [44] 通配符匹配
    • [494] 目标和
    • [509] 斐波那契数
    • [518] 零钱兑换 II
    • [62] 不同路径
    • [676] 实现一个魔法字典
    • 70 爬楼梯
    • [718] 最长重复子数组
    • [78] 子集
    • [82] 删除排序链表中的重复元素 II
    • [871] 最低加油次数
    • [88] 合并两个有序数组
    • [887] 鸡蛋掉落
    • 958.二叉树的完全性检验
    • [98] 验证二叉搜索树
    • [983] 最低票价
    • leetcode practice
    • 约瑟夫问题
    • 移除重复节点
  • linked-list

    • 706. 设计哈希映射
    • 链表
  • stack

    • stack
  • tree

    • Tree Traversal
    • 二叉树的最近公共祖先
    • 二叉树
    • 题目
  • leetCode 刷题
  • 回溯
  • 排序算法

[234] 回文链表

要判断一个链表是否是回文链表,可以使用以下步骤:

  1. 快慢指针找到中间节点:使用快慢指针法找到链表的中间节点。快指针每次移动两步,慢指针每次移动一步,当快指针到达链表末尾时,慢指针刚好到达链表的中间。
  2. 反转链表的后半部分:将链表的后半部分反转。
  3. 比较前半部分和反转后的后半部分:逐个比较这两部分节点的值是否相同。
  4. 恢复链表(可选):将反转的后半部分再反转回去,恢复原链表结构。

以下是实现代码及详细解释:

function ListNode(val) {
    this.val = val;
    this.next = null;
}

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var isPalindrome = function (head) {
    if (head === null || head.next === null) return true;

    // 快慢指针找到中间节点
    let slow = head,
        fast = head;
    while (fast !== null && fast.next !== null) {
        slow = slow.next;
        fast = fast.next.next;
    }

    // 反转后半部分链表
    let prev = null;
    while (slow !== null) {
        let temp = slow.next;
        slow.next = prev;
        prev = slow;
        slow = temp;
    }

    // 比较前半部分和反转后的后半部分
    let left = head,
        right = prev;
    while (right !== null) {
        if (left.val !== right.val) return false;
        left = left.next;
        right = right.next;
    }

    return true;
};

// 测试
let head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(2);
head.next.next.next = new ListNode(1);

console.log(isPalindrome(head)); // 输出 true

详细解释

  1. 找到中间节点:

    • 使用两个指针 slow 和 fast。slow 每次走一步,fast 每次走两步。当 fast 到达链表末尾时,slow 刚好到达中间。
    let slow = head,
        fast = head;
    while (fast !== null && fast.next !== null) {
        slow = slow.next;
        fast = fast.next.next;
    }
    
  2. 反转后半部分链表:

    • 通过遍历从中间节点开始的链表,并反转其指向。
    let prev = null;
    while (slow !== null) {
        let temp = slow.next;
        slow.next = prev;
        prev = slow;
        slow = temp;
    }
    
  3. 比较前半部分和反转后的后半部分:

    • 使用两个指针分别指向前半部分的头和反转后的后半部分的头,逐个比较节点的值。
    let left = head,
        right = prev;
    while (right !== null) {
        if (left.val !== right.val) return false;
        left = left.next;
        right = right.next;
    }
    
  4. 恢复链表(可选):

    • 为了保证链表结构不变,可以将反转的部分再反转回去。这个步骤是可选的,因为它不影响判断链表是否为回文。

通过这种方法,可以在 O(n) 时间复杂度和 O(1) 空间复杂度内判断链表是否为回文。

Last Updated:
Contributors: rosendo
Prev
[2306] 公司命名
Next
[2516] 每种字符至少取 K 个