持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
题目(Palindrome Linked List)
链接:https://leetcode-cn.com/problems/palindrome-linked-list
解决数:3046
通过率:52.5%
标签:栈 递归 链表 双指针
相关公司:amazon microsoft facebook
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
示例 1:
输入: head = [1,2,2,1]
输出: true
示例 2:
输入: head = [1,2]
输出: false
提示:
- 链表中节点数目在范围
[1, 105]内 0 <= Node.val <= 9
进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
思路
只要找到链表的中间位置,以中间位置为分界线,反转前半部分,再用反转了的前半部分与后半部分做对比,如有不同就返回 false。 这一种做法虽然有两次遍历,但两次遍历的长度均为链表个数的一半,所以达到时间复杂度为 。
获取中间值:
设置一个中间指针 mid,在一次遍历中,head 走两格,mid 走一格,当 head 取到最后一个值或者跳出时,mid 就指向中间的值。
let mid = head
// 循环条件:只要head存在则最少走一次
while(head !== null && head.next !== null) {
head = head.next.next // 指针一次走两格
mid = mid.next// 中间指针一次走一格
}
反转前部分节点:
遍历的时候通过迭代来反转链表,mid 之前的 node 都会被反转。 使用迭代来反转。
while(head !== null && head.next !== null) {
// 这个赋值要在mid被修改前提前
pre = mid
// 遍历链表
mid = mid.next
head = head.next.next
// 反转前面部分的节点,并用reversed保存
pre.next = reversed
reversed = pre
}
注意:
奇数偶数的情况略有不同,奇数情况下,在判断值是否相同时 mid 要往后走一位。
例如: 奇数:1 -> 2 -> 3 -> 2 ->1 遍历完成后:mid = 3->2->1 reversed = 2->1
偶数:1 -> 2 -> 2 ->1 遍历完成后:mid = 2->1 reversed = 2->1
完整代码如下:
var isPalindrome = function(head) {
if(head === null || head.next === null) return true;
let mid = head;
let pre = null;
let reversed = null;
// end每次走两格,这个循环的时间复杂度为O(n/2)
while(head !== null && head.next !== null) {
// 这个赋值要在mid被修改前提前
pre = mid
// 遍历链表
mid = mid.next
head = head.next.next
// 反转前面部分的节点,并用reversed保存
pre.next = reversed
reversed = pre
}
// 奇数mid往后走一位
if(head) mid = mid.next
while(mid) {
if(reversed.val !== mid.val) return false
reversed = reversed.next
mid = mid.next
}
return true
};