234.回文链表
给你一个单链表的头节点 head
,请你判断该链表是否为回文链表。如果是,返回 true
;否则,返回 false
。
示例 1:
输入:head = [1,2,2,1]
输出:true
示例 2:
输入:head = [1,2]
输出:false
解题思路与代码
1.转换为数组 再用双指针
最简单的
时间、空间复杂度都是O(n)的算法
var isPalindrome = function(head) {
const list = [];
while(head != null){
list.push(head.val);
head = head.next;
}
//转变为数组后 双指针秒杀
for(let i = 0, j = list.length - 1;i < j;i++, j--){
let head = list[i];
let tail = list[j];
if(head != tail){
return false;
}
}
return true;
};
2.高级一些的链表双指针
就是 官方题解的方法三 的思路 基本上是一样的~ 实现方法要比题解三简便些~
照着这个逻辑看下去 配合图 肯定能懂~
自己画了个图 有点丑 凑合看~
-
【1】搞快慢指针 快指针到尾部时 结束循环 获得slow(此时slow指向链表后半部分的开头 用于和“前半部分的局部反转”进行对比)
-
【2】翻转一下链表 得到的即为 prepre(具体知识见 leetcode206 设置一个虚拟的prepre 与pre打个配合 得到局部的反转链表)
-
【3】比较现在的慢指针(后半部分链表) 与 反向过来的前半部分链表 即可
奇数也同理啦 不过需要一步
if(fast != null){
slow = slow.next;
}
代码实现
// 搞快慢指针 快指针到尾部 慢指针刚好遍历完前半部分
var isPalindrome = function(head) {
let fast = head;
let slow = head;//快慢指针用于让slow指向链表后半部分的开头
let pre = head, prepre = null;//反转指针的原理 详见leetcode206
while(fast != null && fast.next != null){
//01 快慢指针 获得链表
fast = fast.next.next;
slow = slow.next;
//02 反转前半部分链表
pre.next = prepre;
prepre = pre;
pre = slow;//slow指向的正好是pre下一步要指向的位置
}
//如果结点数为奇数个 slow要再往下指一位(具体看图)
if(fast != null){
slow = slow.next;
}
//接下来比较前半部分的反转和后半部分即可
while(slow != null){
if(slow.val != prepre.val){
return false;
}
slow = slow.next;
prepre = prepre.next;
}
return true;
};