思路1:辅助栈,我们知道链表是无法从后往前遍历的,而栈是先进后出的,所以我们将原链表节点和栈顶节点一一比较即可。时间O(N) 空间O(N)。
【注:这里不能使用反转链表中的将原链表节点一个一个取下形成新链表 的方式,因为这样是破坏了原链表,而我们后续需要对原链表进行遍历的。可以利用栈的先进后出的特点,形成新的链表。虽然前者空间复杂度是O(1)但是不可采取,后者是O(N)】
class Solution {
public boolean isPalindrome(ListNode head) {
Stack<ListNode> stack=new Stack();
ListNode temHead=head;
while(temHead!=null)
{
stack.push(temHead);
temHead=temHead.next;
}
ListNode dummy=new ListNode(-1);
ListNode node=dummy.next;
while(head!=null)
{
if(head.val!=stack.pop().val)
{
return false;
}
head=head.next;
}
return true;
}
}
复习:栈的使用
Stack stack=new Stack ();
入栈stack.push(),出栈stack.poll()
思路2:将链表中的值存入数组,然后双指针。复杂度同思路1
思路3:快慢指针+双指针+原链表部分反转 复杂度:时间O(N) 空间O(1)
由于回文的特殊性,可以不完全反转链表,而是仅仅反转部分链表,将空间复杂度降到 O(1)
1、快慢指针找中点
2、后半部分反转
3、双指针遍历比较
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null)
{
fast=fast.next.next;
slow=slow.next;
}
if(fast!=null)
{
slow=slow.next;
}
ListNode right=reverse(slow);
ListNode left=head;
while(right!=null)
{
if(left.val!=right.val)
{
return false;
}
left=left.next;
right=right.next;
}
return true;
}
private ListNode reverse(ListNode head)
{
ListNode pre=null;
ListNode cur=head;
ListNode nxt=cur;
while(cur!=null)
{
nxt=cur.next;
cur.next=pre;
pre=cur;
cur=nxt;
}
return pre;
}
}
反转部分复杂一点,pre 当前节点的前一节点,cur当前要反转的节点,nxt防止链表断开,指向下一个要反转的节点【nxt先指向cur,在cur.next反向之前,nxt就先把cur的下一个反转节点记录下来】