解题思路
快慢指针+反转半截链表一起操作,可以实现 O(n) 的时间复杂度和 O(1) 的空间复杂度。
当快指针停下来的时候,慢指针一定是走到了最中间,但是这里要注意,退出的时候中间指针的方向还没有改变,因为我们后面还需要用到这个中间指针,所以在退出循环之后对中间的节点进行一下反转。
然后,回文有两种情况,一种是奇数个节点,中间节点不考虑;另一种是偶数个节点,中间节点是两个,所以分别对这两种情况进行判断即可。
另一种方法是先把链表转成数组,然后就可以很方便的用双指针进行判断了,不过空间复杂度变成了 O(n).
代码
/**
* 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.next==null) return true;
if (head.next.next==null){
if (head.val==head.next.val) return true;
else return false;
}
ListNode pre = null;
ListNode cur = head;
ListNode fast = head;
ListNode next = null;
//反转链表+快慢指针一起操作
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
//退出循环后,中间节点也要反转
next=cur.next;
cur.next=pre;
//假设cur和next都是中间
ListNode left=cur,right=next;
while (left != null && right != null && left.val == right.val) {
left = left.next;
right = right.next;
}
if (left==null && right==null) return true;
//假设cur自己是中间
left=cur.next;
right=next;
while (left != null && right != null && left.val == right.val) {
left = left.next;
right = right.next;
}
if (left==null && right==null)
return true;
else return false;
}
//转数组再双指针
public boolean isPalindrome(ListNode head) {
StringBuilder sb = new StringBuilder();
while (head != null) {
sb.append(head.val);
head = head.next;
}
int l = 0, r = sb.length() - 1;
while (l <= r && sb.charAt(l) == sb.charAt(r)) {
l++;
r--;
}
if (l >= r) return true;
else return false;
}
}