题目
题目链接:leetcode-cn.com/leetbook/re…
题解
1、借助数组
前面字符串的题目中有一题是验证回文串,而这题是验证回文链表,我们可以用一个数组将链表的所有值存下来,然后再使用双指针验证是否是回文数组;
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var isPalindrome = function(head) {
let temp = head;
let arr = [];
let front = 0,
rear = 0;
while(temp != null) {
arr.push(temp.val);
temp = temp.next;
}
rear = arr.length - 1;
while(rear >= front) {
if(arr[rear] ^ arr[front]) {
return false;
}
rear--;
front++;
}
return true;
};
2、先获取链表长度,再递归
借助辅助数组固然方便,但其空间复杂度也达到了 o(n),接下来不使用辅组数组,直接对链表操作;
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var isPalindrome = function(head) {
let len = 0,
half = 0;
let temp = head;
let flag = false;
let isodd = false;
// 求链表长度
while(temp) {
len++;
temp = temp.next;
}
half = Math.ceil(len/2);
if(len%2 === 1) {
isodd = true;
}
// 递归函数
function compare(head,half) { // 这里的递归函数使用了全局变量,在其它地方复用这个递归函数
if(half === 0) {
return head;
}
const h = compare(head.next,half - 1);
if(half === 1 && isodd) { // 通过 isodd 这个全局变量来判断链表是否是奇数
return h;
}
if(head.val !== h.val) {
flag = true; // 使用 flag 这个全局变量来标识在 递归 的过程中链表对称位置上的元素是否有不 相等的
}
return h.next;
}
compare(head,half);
if(flag) {
return false;
}
return true;
};
上面的代码中的递归函数因为使用了全局变量,所以递归函数将无法被复用在其它地方,下面给出可以复用的递归函数(通过向递归函数传递对象来实现);
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var isPalindrome = function(head) {
let len = 0,
half = 0;
let temp = head;
let flag = {flag:false};
let isodd = false;
// 求链表长度
while(temp) {
len++;
temp = temp.next;
}
half = Math.ceil(len/2);
if(len%2 === 1) {
isodd = true;
}
// 递归函数
function compare(head,half,isodd,flag) { // 改成可以复用的形式~,将 flag 改成对象传进去;
if(half === 0) {
return head;
}
const h = compare(head.next,half - 1,isodd,flag);
if(half === 1 && isodd) { // 通过 isodd 这个全局变量来判断链表是否是奇数
return h;
}
if(head.val !== h.val) {
flag.flag = true; // 使用 flag 这个全局变量来标识在 递归 的过程中链表对称位置上的元素是否有不相等的
}
return h.next;
}
compare(head,half,isodd,flag);
if(flag.flag) {
return false;
}
return true;
};
全量比较 n 次
上面两个递归算法使用的递归都只是链表的前半段和后半段比较,比较的次数为 n/2 ,这样就会需要考虑复杂的边界条件,即要找出中间位置,并且要在中间位置开始比较;
链表的前半段与后半段对称,这是回文链表的定义;链表反转后和原链表相等,这也是回文链表的定义;
因此可以写比较 n 次的算法,这种算法相对于比较 n/2 次的算法更好写;
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var isPalindrome = function(head) {
let temp = head;
let flag = false;
function compare(head,temp) {
if(head === null){
return temp;
}
const t = compare(head.next,temp);
if(t.val !== head.val) {
flag = true;
}
return t.next;
}
compare(head,temp);
if(flag) {
return false;
}
return true;
};
大家如果有更好的思路和解法,欢迎大家一起来讨论啊~
这是使用 JavaScript 对 LeetCode《初级算法》的每道题的总结和实现的其中一篇,汇总篇在这里: