回文链表
难度:简单
题目链接:https://leetcode-cn.com/problems/palindrome-linked-list/
题目:
请判断一个链表是否为回文链表
示例1:
输入:1->2
输出:false
示例2:
输入:1->2->2->1
输出:true
法一:
/**我的思路**/
/*
用list将所有节点的val存下来,用双指针判断即可
*/
/**我的代码**/
import java.util.ArrayList;
import java.util.List;
public class 回文链表 {
public static boolean isPalindrome(ListNode head) {
List<Integer> list = new ArrayList<>();
while(head != null){
list.add(head.val);
head = head.next;//指向下一个节点
}
int left = 0;
int right = list.size()-1;
while(left < right){
if(!list.get(left).equals(list.get(right))) return false;
left++;
right--;
}
return true;
}
//题目给出的类
public static class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
}
法二:
/**他人思路**/
/*
哈希公式:hash = hash * seed + val,其中 seed 是一个质数,val是节点的值
那么,顺序哈希的结果为:hash1=a[1]*seed^(n-1)+a[2]*seed^(n-2)+...+a[n-1]*seed^1+a[n]*seed^0
逆序哈希的结果为:hash2=a[1]*seed^0+a[2]*seed^1+...+a[n-1]*seed(n-2)+a[n]*seed^(n-1)
我们发现,逆序哈希的结果也能正序计算得出
最后比较 hash1 == hash2
提示:哈希过程中肯定会超出long的范围,其实无所谓,变成负数照样可以。
*/
/**他人代码**/
class Solution {
public boolean isPalindrome(ListNode head) {
long hash1 = 0, hash2 = 0, h = 1;
long seed = (long) (1e9 + 7);
ListNode p = head;
while (p != null) {
hash1 = hash1 * seed + p.val;
hash2 = hash2 + h * p.val;
h *= seed;
p = p.next;
}
return hash1 == hash2;
}
}
作者:tcan1993
链接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/ha-xi-bian-li-yi-ci-jiu-xing-by-tcan1993/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
法三:
/**他人思路**/
/*
反转后半部分链表
这题是让判断链表是否是回文链表,所谓回文链表就是以中间为中心点两边对称,我们常见的有判断一个字符串是否是回文字符串,这个比较简单,可以使用两个指针,一个最左边一个最右边,两个指针同时往中间靠,判断所指的字符是否相等。但是这题判断的是链表,因为这里是单向链表,只能从前往后访问,所以使用判断字符串的那种方式行不通。但我们可以通过找到链表的中间节点然后把链表的后半部分反转,最后再用后半部分反转的链表和前半部分的链表的前半部分一一比较即可。
*/
/**他人代码**/
public boolean isPalindrome(ListNode head) {
ListNode fast = head, slow = head;
//通过快慢指针找到中点
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
//如果fast不为空,说明链表的长度是奇数个
if (fast != null) {
slow = slow.next;
}
//反转后半部分链表
slow = reverse(slow);
fast = head;
while (slow != null) {
//然后比较,判断节点值是否相等
if (fast.val != slow.val)
return false;
fast = fast.next;
slow = slow.next;
}
return true;
}
//反转链表
public ListNode reverse(ListNode head) {
ListNode prev = null;
while (head != null) {
ListNode next = head.next;
head.next = prev;
prev = head;
head = next;
}
return prev;
}
作者:sdwwld
链接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/di-gui-zhan-deng-3chong-jie-jue-fang-shi-zui-hao-d/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
法四:
/**他人思路**/
/*
使用栈解决
我们知道栈是一种先进后出的数据结构,这里还可以使用栈先把链表的节点全部存到栈中,然后再一个个出栈,这样就相当于链表从后往前访问了,通过这种方式也能解决。
*/
/**他人代码**/
public boolean isPalindrome(ListNode head) {
ListNode temp = head;
Stack<Integer> stack = new Stack();
//把链表节点的值存放到栈中
while (temp != null) {
stack.push(temp.val);
temp = temp.next;
}
//然后再出栈
while (head != null) {
if (head.val != stack.pop()) {
return false;
}
head = head.next;
}
return true;
}
作者:sdwwld
链接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/di-gui-zhan-deng-3chong-jie-jue-fang-shi-zui-hao-d/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
法五:
/**他人思路**/
/*
递归方式解决
我们知道,如果对链表逆序打印可以这样写*/
private void printListNode(ListNode head){
if(head == null) return;
printListNode(head.next);
System.out.println(head.val);
}
/*
也就是说最先打印的是链表的尾结点,他是从后往前打印的。
*/
/**他人代码**/
ListNode temp;
public boolean isPalindrome(ListNode head) {
temp = head;
return check(head);
}
private boolean check(ListNode head) {
if (head == null)
return true;
boolean res = check(head.next) && (temp.val == head.val);
temp = temp.next;
return res;
}
作者:sdwwld
链接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/di-gui-zhan-deng-3chong-jie-jue-fang-shi-zui-hao-d/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
小结:
效率对比:法二=法三>法五>法一>法四(法一和法四几乎相同)
方法对比:
法一:取长度,双指针对比
法二:哈希数
法三:快慢指针遍历比较
法四:利用栈的性质解决
法五:递归
快慢指针用法巧妙,第一次见,以后遇到类似问题可加以尝试。哈希做法没见过,这次加深了解。