你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
题目要求O(1)空间复杂,而方法:数组遍历保存元素需要额外数组变量O(n)、递归回溯方式需要栈内存O(n);
一种方法是用快慢指针获得链表的中间点,然后对后半段逆序再分别比较前(正)后(逆)两段;
也可以在慢指针遍历的过程中同时对前半段逆序,然后比较前(逆)后(正)两段;时间O(n),空间O(1);
Java Code:
public static boolean isPalindrome(ListNode head) {
if(head == null || head.next == null) return true;
ListNode pre = head, prepre = head, slow = head, fast = head;
//对前半段链表逆序
while(fast!=null && fast.next!=null) {
pre = slow;
slow = slow.next;
fast = fast.next.next;
pre.next = prepre;
prepre = pre;
}
if(fast != null)
slow = slow.next;
//前后两段比较
while(pre!=null && slow!=null) {
if(pre.val!=slow.val)
return false;
slow = slow.next;
pre = pre.next;
}
return true;
}
这种方法满足了题目要求,但是题目要求我们判断,而逆序操作显然修改了原链表;
但是力扣大神给出了不修改原链表,且满足时间空间复杂的奇妙方法,我愿称之为绝活(doge);
Hash Method
构造哈希函数:hash = hash * seed + val,其中seed表示一个质数,val表示节点的值;
分析回文链表的特点,我们可以得到,对于一个回文链表,其正序hash值应该等于逆序hash值;
Java Code:
public static boolean isPalindromeHash(ListNode head) {
if(head == null || head.next == null) return true;
int hash1 = 0, hash2 = 0, h = 1, seed = (int) 1e2+7;
while(head!=null) {
//正序hash值
hash1 = hash1 * seed + head.val;
//逆序hash值
hash2 = hash2 + h * head.val;
h *= seed;
head = head.next;
}
return hash1 == hash2;
}