解题思路
1快慢指针同时遍历单链表。快指针一下走两步,慢指针一下走一步。
2当快指针走到结尾时,即慢指针走到中间。
3若此时从中间往两端走,则可比较是否为回文。执行时间因为根据链表的量级而变化而变化,而先后遍历链表为一次,故时间复杂度为O(n)。
4下面思考如何判断快指针走到结尾。当快指针再链表倒数第二个节点时,快指针前进,则此时快指针指向null。此种情况之下,快指针不能再前进了。所以当fast&&fast.next(区别于快指针落到最后一个节点时不能再前进了)为真时才能前进。
5慢指针走到中间时,想要往回走,就要在来的路上边走边更改next指向。保存慢指针下一步该到的位置,更改完当前位置下的next为保存的pre之后,慢指针直接跳到next。
6当跳出第一个while之后,要区分链表长度为奇数还是偶数。当遍历结束时,fast指针为真时,此链表为奇数。反之为偶数。当链表为奇数时,一个指针从此时的pre往反方向走,另一个要从当前slow指针的next指针开始走。
7注意一点当链表只有一个节点时不会进while,所以需要单独讨论。
// 回文字符串-链表实现
//1.用类去实现链表的结构
class Node{
constructor(val){
this.val = val;
this.next = null;
}
}
/*
用数组作为入参,单链表作为返回值
*/
const arrayToLinkNode = (arr)=>{
// 需要一个移动指针
// 还需要一个头指针-最后返回这个头指针
let head = new Node(arr[0]);
let cur = head;
for(let i = 1; i < arr.length; i++){
cur.next = new Node(arr[i]);
cur = cur.next;
}
return head;
}
console.log('--arrayToLinkNode', arrayToLinkNode([1,2,3,4,5]))
// 回文链表
// 慢指针和快指针一起走,慢指针尾插法进行反转,快指针用来判断走到尾了结束掉慢指针的尾插行为
// 最后将慢指针的值和后半部分的指针的值进行逐个对比
const isPalindrome = (head)=>{
let fast = head;
let slow = head;
let pre = null;
let next = null;
// 这个判断条件,当fast和fast.next
while(fast&&fast.next){
fast = fast.next.next;
next = slow.next;
slow.next = pre;
pre = slow;
slow = next;
}
if(fast){
slow = slow.next;
}
while(pre){
if(pre.val !== slow.val){
return false;
}
pre = pre.next;
slow = slow.next;
}
return true;
}
console.log('--',isPalindrome(arrayToLinkNode([1,2,3,4,5])))