算法-判斷鏈表是否爲迴文鏈表
1、判斷鏈表是否爲迴文鏈表
題目來源:Leetcode234,是一道easy題。
請判斷一個鏈表是否爲迴文鏈表。
示例 1:
輸入: 1->2
輸出: false
示例 2:
輸入: 1->2->2->1
輸出: true
進階:
你能否用 O(n) 時間複雜度和 O(1) 空間複雜度解決此題?
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/palindrome-linked-list
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
我們知道單向鏈表只有指向後面的指針,所以不能像數組那樣,從兩端向中間遍歷,不過。
很自然的,我們可以利用棧的性質來存儲鏈表,然後彈出和原鏈表比較,時空複雜度爲N/N
/**
* 用棧性質實現
* @param head
* @return
*/
public boolean isPalindrome(ListNode head){
Stack<ListNode> stack=new Stack<>();
ListNode curr=head;
while (curr!=null){
stack.push(curr);
curr=curr.next;
}
while (head!=null){
if(head.val!=stack.pop().val){
return false;
}
head=head.next;
}
return true;
}
然而,面試官一般不會就這樣放過我們,讓我們在時空複雜度上進行優化。從時間複雜度上來說,已經做到了2*N(入棧出棧),這題目也不可能用二分法優化的log(n),所以,我們可以從空間複雜度上入手。
迴文字符的定義是什麼?圍繞着中點對稱,由此,我們可以先找到鏈表的中點,把鏈表分爲兩部分,這兩部分是逆序排列的,於是,我們可以將前一段鏈表反轉,然後和後一段鏈表進行比較!
涉及到的知識
1、鏈表反轉問題,在我之前發的文章中有非常詳細的解釋,這裏就不多說了。
2、尋找鏈表中點問題,思路是快慢指針,在前面文章也有解讀
/**
* 解題思路:在找中點的時候對前半部分進行翻轉,時空複雜度爲n和1
* @param head
* @return
*/
public boolean isPalindrome(ListNode head){
if(head==null||head.next==null){
return true;
}
ListNode quick=head;
ListNode slow=head;
ListNode prev=null;
ListNode curr=head;
while (quick!=null&&quick.next!=null){
ListNode temp=slow.next;
quick=quick.next.next;
slow=slow.next;
curr.next=prev;
prev=curr;
curr=temp;
}
if(quick!=null){//奇數個元素,跳過中間節點
slow=slow.next;
}
ListNode frontNode=prev;
while (frontNode!=null){
if(frontNode.val!=slow.val){
return false;
}
frontNode=frontNode.next;
slow=slow.next;
}
return true;
}
值得注意的是,在尋找鏈表中點的過程中,如果鏈表長度爲偶數,慢指針最終指向中點靠後的那個節點,快指針爲null,如果鏈表長度爲奇數,那麼慢指針最終指向正中間的節點,因此,在比較之前需要指向自己的後一個節點。