回文就是正着念,反着念是一样的,给出了3种解
首先正着最先得数得在右半部分会最后一个,满足栈的先进后出特性所以可以用一个栈来解决这个问题
用N个空间
这太简单了不说了
public static boolean isPalindromeList1(ListNode head){
if(head==null||head.next==null){
return true;
}
Stack<Integer> stack = new Stack<>();
ListNode p = head;
while(p!=null){
stack.push(p.val);
p=p.next;
}
p = head;
while(!stack.isEmpty()){
if(stack.pop()!=p.val){
return false;
}
p=p.next;
}
return true;
}
用一半的空间
可以从链表的中点开始,把后半部分压入栈中,然后跟链表的前半部分对比全相同就满足回文
快慢指针法寻找中点,注意循环判断的条件是栈为空,比判断链表中点的位置要简单。。有时候可以换个思路
public static boolean isPalindromeList2(ListNode head){
if(head==null||head.next==null){
return true;
}
Stack<Integer> stack = new Stack<>();
ListNode fast = head.next;
ListNode slow = head;
while(fast!=null&&fast.next!=null){
slow = slow.next;
fast = fast.next.next;
}
while(slow!=null){
stack.push(slow.val);
slow = slow.next;
}
//从链表的后半段判断是否为回文结构
while(!stack.isEmpty()){//判断栈为空
if(head.val!=stack.pop()){
return false;
}
head = head.next;
}
return true;
}
O(1)空间复杂度
思路简单,把链表后半部分逆序然后两个指针往中间走就行
难在边界的判断上
定义三个指针 tail保存已经逆好序的俩表,cur指向要逆序的结点,old保存下一个结点。循环条件为cur!=null cur指向tail 然后tail=cur 然后 cur = old
根据奇偶长度不同,判断条件为两个端点谁指向空就结束(判断回文)
最后别忘了把顺序恢复到正常
public static boolean isPalindromeList3(ListNode head ){
if(head==null||head.next==null){
return true;
}
ListNode fast = head.next;
ListNode slow = head;
while(fast!=null&&fast.next!=null){
slow = slow.next;
fast = fast.next.next;
}
//反转链表
ListNode tail = slow;
ListNode cur = tail.next; //cur = right part frist node
ListNode old = null;
slow.next = null;//mid.next = null
while(cur!=null){//right part convert
old = cur.next; //
cur.next = tail;
tail = cur;
cur = old;
}
// printList(head);
// printList(tail);
//复用两个指针 cur old
cur = head;
old = tail;
while(cur!=null&old!=null){
if(cur.val!=old.val){
return false;
}
cur = cur.next;
old = old.next;
}
cur = tail.next;//not null
//只能从最后一个结点来逆序 因为是单向链表只能顺着方向来
tail.next = null;//last node ->null
while(cur!=null){
old = cur.next;
cur.next = tail;
tail = cur;
cur = old;
}
// printList(head);
return true;
}