解
- 快慢指针找中间节点
- 然后翻转中间节点起始的后半部分链表
- 再用双指针遍历比较值是否相等
- 返回原链表
找中间节点
- 两个快慢指针slow和fast指向head
- fast每次走两步,slow每次走一步
- 终止条件fast.next=null(奇数链表的结束)或fast.next.next=null(偶数链表的结束)
反转链表
- 三个指针当前节点cur,当前节点的后一个节点curNext,当前的节点前一个节点curPre
- 开始反转cur指向curPre,全部后移
- 终止条件cur不为空
代码
/**
* 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){
return true;
}
//找中间节点
ListNode halfNode=half(head);
//翻转后一半链表
ListNode lastNode=reverse(halfNode.next);
//双指针比较
while(lastNode!=null){
if(head.val!=lastNode.val){
return false;
}
head=head.next;
lastNode=lastNode.next;
}
return true;
}
//中间节点
public ListNode half(ListNode head){
ListNode f=head;
ListNode s=head;
//f.next!=null奇数链表结束同时s指向中间节点
//f.next.next!=null偶数链表结束s指向最中间两个节点的左节点
while(f.next!=null&&f.next.next!=null){
s=s.next;
f=f.next.next;
}
return s;
}
//翻转链表
public ListNode reverse(ListNode head){
ListNode pre=null;
ListNode cur=head;
while(cur!=null){
//临时保存cur.next因为后序 cur.next=pre;改变了
ListNode curNext=cur.next;
cur.next=pre;
pre=cur;
cur=curNext;
}
return pre;
}
}
复杂度
时间复杂度O(n) n指的是链表的大小
空间复杂度O(1) 只会修改原本链表中节点的指向,而在堆栈上的堆栈帧不超过 O(1)