文章目录
- 回文链表
- 我的思路
- 网上思路
- 总结
回文链表
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
图一
图二
示例 1:(图一)
输入:head = [1,2,2,1]
输出:true
示例 2:(图二)
输入:head = [1,2]
输出:false
我的思路
循环
网上思路
双指针 和 递归
我的思路
var isPalindrome = function (head) {
if (!head || !head.next) return true;
let slow = head;
let fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
}
let prev = null;
while (slow) {
const next = slow.next;
slow.next = prev;
prev = slow;
slow = next;
}
let left = head;
let right = prev;
while (right) {
if (left.val !== right.val) {
return false;
}
left = left.next;
right = right.next;
}
return true;
};
讲解
- 首先检查链表是否为空或只有一个节点,如果是,则返回 true。
- 使用快慢指针找到链表的中间节点。
- 反转链表的后半部分。
- 比较前半部分和反转后的后半部分,若有不同则返回 false,否则返回 true。
网上思路
// 方法一:
var isPalindrome = function (head) {
const vals = [];
while (head !== null) {
vals.push(head.val);
head = head.next;
}
for (let i = 0, j = vals.length - 1; i < j; ++i, --j) {
if (vals[i] !== vals[j]) {
return false;
}
}
return true;
};
// 方法二:
let frontPointer;
const recursivelyCheck = (currentNode) => {
if (currentNode !== null) {
if (!recursivelyCheck(currentNode.next)) {
return false;
}
if (currentNode.val !== frontPointer.val) {
return false;
}
frontPointer = frontPointer.next;
}
return true;
}
var isPalindrome = function (head) {
frontPointer = head;
return recursivelyCheck(head);
};
讲解
双指针解法
一共为两个步骤:
- 复制链表值到数组列表中。
第一步,需要遍历链表将值复制到数组列表中。用 currentNode 指向当前节点。每次迭代向数组添加currentNode.val,并更新 currentNode = currentNode.next,当 currentNode = null 时停止循环。- 使用双指针法判断是否为回文。
我们在起点放置一个指针,在结尾放置一个指针,每一次迭代判断两个指针指向的元素是否相同,若不同,返回 false;相同则将两个指针向内移动,并继续判断,直到两个指针相遇。
在编码的过程中,注意我们比较的是节点值的大小,而不是节点本身。正确的比较方式是:node_1.val == node_2.val,而 node_1 == node_2 是错误的。递归
currentNode 指针是先到尾节点,由于递归的特性再从后往前进行比较。frontPointer 是递归函数外的指针。若 currentNode.val != frontPointer.val 则返回 false。反之,frontPointer 向前移动并返回 true。
算法的正确性在于递归处理节点的顺序是相反的(回顾上面打印的算法),而我们在函数外又记录了一个变量,因此从本质上,我们同时在正向和逆向迭代匹配。
总结
还是网上的方法简单明了,而且也用了之前学习的内容,我还需要好好学习。