题干
编写一个函数,检查输入的链表是否是回文的。
难度为easy,但是感觉这个小题挺有意思,值的写写
深拷贝并反转链表
- 首先深拷贝链表(这里踩了一个坑,Object.assign({}, head)只能深拷贝head,但是head.next并没有被深拷贝,所以这个不可以;而JSON.parse(JSON.stringfy(head))可以完美深拷贝,但是当数据量过于庞大的时候,会执行栈溢出)
- 反转深拷贝以后的链表
- 比较两个链表
var isPalindrome1 = function(head) {
let reverseHead = reverse(JSON.parse(JSON.stringify(head)))
while (head) {
if (head.val != reverseHead.val) {
return false
}
head = head.next;
reverseHead = reverseHead.next
}
return true
};
function reverse(head) {
let prev = null;
let cur = head;
while (cur) {
let next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev
}
反思:这个方法是最先想到的方法,跳过深拷贝的坑不讲,回文链表其实只需要比较前一半就可以,而这个方法不知道链表的中点在哪里,只能比较全部链表,做了很多无用功。
将链表分别以正序和倒序存在两个不同的数组,比较两个数组
- 设置两个数组
- 循环链表,push与unshift方法向两个数组中依次存值
- 比较两个数组的前半部分
var isPalindrome1 = function(head) {
let arr = [];
let arr_ = [];
while (head) {
arr.push(head.val)
arr_.unshift(head.val)
head = head.next
}
for (let i = 0; i < parseInt(arr.length / 2); i++) {
if (arr[i] != arr_[i]) {
return false
}
}
return true
};
反思:这个方法的确可以少做那一半的无用功,但是向数组存值是一个更耗时间的操作,还不如上一个呢
出入栈法
- 算出链表长度并算出中点位置
- 遍历链表,遍历中点前的元素时,向栈中存数据,遍历链表中点后的数据时,从栈中取数据。
- 后半部分当前遍历值与取出的值不相符的话,就不为回文,一样的话就是回文
var isPalindrome = function(head) {
let len = getLen(head);
let mid = Math.floor(len / 2);
let arr = [];
let index = 0;
if (len % 2 == 0) {
while (head) {
if (index < mid) {
arr.push(head.val);
} else {
let tmp = arr.pop();
if (tmp != head.val) {
return false
}
}
index++;
head = head.next
}
return true
} else {
while (head) {
if (index < mid) {
arr.push(head.val);
} else if (index == mid) {
} else {
let tmp = arr.pop();
if (tmp != head.val) {
return false
}
}
index++;
head = head.next
}
return true
}
};
function getLen(head) {
let result = 0;
while (head) {
result++;
head = head.next;
}
return result
}
反思:这个方法写起来很麻烦,因为要判断链表长度为单数还是双数,并且依然需要向数组存取值,性能消耗也不小
反转链表后半部分
- 快慢指针法,找到链表中点并返回
- 将中点.next反转
- 比较原数组与反转后的链表
var isPalindrome = function(head) {
if (!head) return true;
let midReverse = reverse(getMid(head).next);
while (midReverse) {
if (midReverse.val != head.val) {
return false
}
midReverse = midReverse.next;
head = head.next;
}
return true
}
function getMid(head) {
let fast = slow = head;
while (fast.next && fast.next.next) {
fast = fast.next.next;
slow = slow.next;
}
return slow
}
function reverse(head) {
let prev = null;
let cur = head;
while (cur) {
let next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev
}
反思:此方法不需要向数组存值,也不需要做一半的无用功。nice