本文正在参与掘金团队号上线活动,点击 查看大厂春招职位
一、题目描述:
二、思路分析:
分析题目,像我这种刷题菜鸟,想到的第一个的解题思路就是——存储所有值后再校验:
- 将链表的值遍历后复制到一个数组里面
- 基于双指针左右遍历,判断是否为回文数组
/**
* @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;
};
这种做法时间和空间复杂度都是
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;
};
四、总结:
虽然是简单题,但是实际写起来还是很难啊,特别是不熟悉链表操作的情况下。最好将反转链表和快慢指针的题目多写几遍,强化下记忆。
本文正在参与「掘金 4 月刷题打卡活动」, 点击查看 活动详情