234. 回文链表
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
示例 1:
输入:head = [1,2,2,1]
输出:true
示例 2:
输入:head = [1,2]
输出:false
提示:
链表中节点数目在范围[1, 105] 内
0 <= Node.val <= 9
进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
这是一道经典的链表题目,我将用三种解法依次进阶解决。
解法一:用额外O(n)的空间 建立一个栈,遍历链表将结点放进去,最后栈里的元素是链表结点逆序的存放,然后同时开始遍历链表和弹出栈元素,只要结点值不相等,就可以返回false,不是回文链表,否则最后返回true
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
Stack<ListNode> stack = new Stack<>();
ListNode cur = head;
while(cur != null){
stack.push(cur);
cur = cur.next;
}
while(head != null){
if(head.val != stack.pop().val){
return false;
}
head = head.next;
}
return true;
}
}
解法二:栈+快慢指针。原理其实是对栈的空间做一个优化,我们只需要将链表的右半部分放入栈,然后再遍历链表结点和栈弹出的结点作比较,只要结点值不相等,就可以返回false,不是回文链表,否则最后返回true。那么怎么做到只放入右半部分呢,这时候就要用到快慢指针,而且这个快慢指针还有讲究,我们需要做到快指针遍历到最后时,慢指针此时为右半部分的第一个结点,无论结点数是否为奇偶。这时候就要做些细节的调优,快指针指向第一个结点,慢指针指向第一个结点的下一个,快指针走两步,慢指针走一步,这样就能达到需要的条件
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
if(head == null || head.next == null){
return true;
}
ListNode slow = head.next;
ListNode fast = head;
while(fast.next != null && fast.next.next != null){
slow = slow.next;
fast = fast.next.next;
}
Stack<ListNode> stack = new Stack<>();
while(slow != null){
stack.push(slow);
slow = slow.next;
}
while(!stack.isEmpty()){
if(head.val != stack.pop().val){
return false;
}
head = head.next;
}
return true;
}
}
解法三:快慢指针+有限几个变量。这时候不再使用额外空间,我们依旧是快慢指针,但是需要将后半部分做一个反转处理,然后再从左右端点开始依次走向中间遍历比较,只要结点值不相等,就可以返回false,不是回文链表,否则最后返回true。此时快慢指针的设计也有所讲究,需要使得快指针走完,慢指针就指向中间结点(奇数)或者中点的上一个结点(偶数),然后开始对后面的链表进行反转,另外,在比较完之后还要将链表反转回来,使得我们是原地处理链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
if(head == null || head.next == null){
return true;
}
ListNode slow = head;
ListNode fast = head;
while(fast.next != null && fast.next.next != null){
slow = slow.next;
fast = fast.next.next;
}
fast = slow.next;
slow.next = null;
ListNode p = null;
//把后半部分反转
while(fast != null){
p = fast.next;
fast.next = slow;
slow = fast;
fast = p;
}
p = slow;
fast = head;
boolean res = true;
while(slow != null && fast != null){
if(slow.val != fast.val){
res = false;
break;
}
slow = slow.next;
fast = fast.next;
}
slow = p.next;
p.next = null;
//反转回来
while(slow != null){
fast = slow.next;
slow.next = p;
p = slow;
slow = fast;
}
return res;
}
}