LeetCode 234. 回文链表 |刷题打卡

181 阅读2分钟

本文正在参与掘金团队号上线活动,点击 查看大厂春招职位

一、题目描述:

image.png

二、思路分析:

分析题目,像我这种刷题菜鸟,想到的第一个的解题思路就是——存储所有值后再校验

  • 将链表的值遍历后复制到一个数组里面
  • 基于双指针左右遍历,判断是否为回文数组
/**
 * @param {ListNode} head
 * @return {boolean}
 */
var isPalindrome = function (head) {
    let vals = [];
    let node = head;
    while (node) {
        vals.push(node.val);
        node = node.next;
    }
    let i = 0, len = vals.length - 1;
    while (i < len / 2) {
        if (vals[i] !== vals[len - i]) {
            return false;
        }
        i++;
    }
    return true;
};

image.png 这种做法时间和空间复杂度都是 O(n); 但是,需要使用两次遍历过程,性能上表现一般。那么,我们有没有办法优化呢?

这就引出第二种做法,我们能否不使用额外的空间进行值存储呢?使用 快慢指针 + 反转链表 试试(参考 LeetCode 上的题解来理解下这种思路):

三、AC 代码:

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var isPalindrome = function (head) {
    let fast = head, slow = head;
    let cur = head, pre = null;
    while (fast && fast.next) {
        // 当前节点指向慢指针,可以理解成 cur.next
        cur = slow;
        // 慢指针每次步进一步
        slow = slow.next;
        // 快指针每次步进两步
        fast = fast.next.next;
        // 下一个节点指向前一个节点
        cur.next = pre;
        // 前一个节点变成当前节点
        pre = cur;
    }
    // 当快指针到达时,慢指针刚好到达中点,处理特殊情况:
    if (!!fast) {
        slow = slow.next;
    }
    // 从中点开始,左右依次比较
    while (slow && cur) {
        if (slow.val !== cur.val) {
            return false;
        }
        slow = slow.next;
        cur = cur.next;
    }
    return true;
};

image.png

四、总结:

虽然是简单题,但是实际写起来还是很难啊,特别是不熟悉链表操作的情况下。最好将反转链表和快慢指针的题目多写几遍,强化下记忆。

本文正在参与「掘金 4 月刷题打卡活动」, 点击查看 活动详情