數據結構與算法 | 迴文鏈表檢測

pexels-photo-747964

原文連接:wangwei.one/posts/java-…html

如何判斷一個單鏈表是否爲迴文鏈表?java

迴文鏈表

LeetCode 234. Palindrome Linked List算法

例1:bash

Input: 1->2
Output: false
複製代碼

例2:數據結構

Input: 1->2->2->1
Output: true
複製代碼

提高: 時間複雜度爲O(n),空間複雜度爲O(1).函數

解法一

直接將鏈表進行 反轉 ,而後將新的反轉鏈表與原鏈表進行比較,這種思路最爲簡單粗暴。post

此種解法的時間複雜度爲O(n),空間複雜度爲O(n).性能

代碼

/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
    
    public boolean isPalindrome(ListNode head) {
        if(head == null){
            return true;
        }
        ListNode newCurr = null;
        ListNode newPrev = null;
        ListNode curr = head;
        while(curr != null){
            newCurr = new ListNode(curr.val);
            newCurr.next = newPrev;
            newPrev = newCurr;
            curr = curr.next;
        }
        
        ListNode p1 = newCurr;
        ListNode p2 = head;
        
        while(p2 != null && p2 != null){
            if(p2.val != p1.val){
                return false;
            }
            p1 = p1.next;
            p2 = p2.next;
        }
        return true;
    }
}

複製代碼

LeetCode性能測試:測試

Runtime: 3 ms, faster than 24.01% of Java online submissions forPalindrome Linked List.spa

解法二

爲了下降空間複雜度到O(1),咱們能夠只對鏈表的後半部分直接反轉,而後將反轉後的後半部分與前半部分進行比較。

如何對後半部分進行反轉呢?這就涉及到咱們前面的 如何找到中間節點 的方法,使用快慢指針,先找到中間節點,而後從中間節點開始反轉。

須要注意的是,在進行比較時,要之後半部分爲基準進行遍從來比較,例如在鏈表長度位偶數的狀況下:

A -> B -> C -> C -> B -> A 反轉獲得 A -> B -> C -> C <- B <- A,之前半部分爲基準的話,會出現 null 指針的異常。

此種解法的時間複雜度爲O(n),空間複雜度爲O(1).

代碼

/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
    
    public boolean isPalindrome(ListNode head) {
        if(head == null){
            return true;
        }
        
        // 先找到中間節點,slow最後的結果就是中間節點
        ListNode slow = head;
        ListNode fast = head;
        
        for(ListNode curr = slow; slow != null; ){               
            if(fast == null || fast.next == null){
                break;
            }else{
                fast = fast.next.next;
            }
            slow = slow.next;
        }
        
        // 從slow開始,對後鏈表後半部分進行反轉
        ListNode prev = null;
        ListNode curr = slow;
        ListNode next = null;
        
        while(curr != null){
            next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        
        // 對先後兩個部分進行比較
        ListNode p1 = head;
        ListNode p2 = prev;
        
        while(p2 != null){
            if(p1.val != p2.val){
                return false;
            }
            p1 = p1.next;
            p2 = p2.next;
        }     
        return true;
    }
}
複製代碼

LeetCode性能測試:

Runtime: 1 ms, faster than 93.05% of Java online submissions forPalindrome Linked List.

解法三

解法三比較巧妙,不容易想到。思路以下:

  • 定義左右兩個指針,左指針向有移動,"右指針向左移動",對比左右兩個指針是否配置。
  • 咱們這裏是單鏈表,右指針怎麼向左移動呢?這裏經過遞歸的方式,當遞歸函數一層一層返回時,變相地實現了"右指針左移"的思路。

代碼

/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
    
    private ListNode head;
    private ListNode left;
        
    public boolean isPalindrome(ListNode head1) {
        head = head1;
        return isPalindromeUtil(head1);
    }
    
    private boolean isPalindromeUtil(ListNode right){ 
        left = head; 
        
        // 當指向NULL時,中止遞歸
        if (right == null){
            return true; 
        } 
  
        // 向右移動指針,遞歸調用
        boolean isp = isPalindromeUtil(right.next); 
        if (isp == false){
            return false; 
        } 
  
        // 比較左右指針是否匹配
        boolean isp1 = (right.val == left.val); 

        // 移動左指針
        left = left.next; 
  
        return isp1; 
    } 
}
複製代碼

LeetCode性能測試:

Runtime: 3 ms, faster than 22.70% of Java online submissions forPalindrome Linked List.

相關練習

參考資料

相關文章
相關標籤/搜索