ARTS打開第九周

Algorithm:Leetcode 234. 迴文鏈表
https://leetcode-cn.com/problems/palindrome-linked-list/submissions/
請判斷一個鏈表是否爲迴文鏈表。

示例 1:

輸入: 1->2
輸出: false
示例 2:

輸入: 1->2->2->1
輸出: true
進階:
你能否用 O(n) 時間複雜度和 O(1) 空間複雜度解決此題?

解法一:先遍歷一遍,將原鏈表全部反轉得到一個新鏈表;再遍歷一遍,將新舊兩個鏈表逐個比較。時間複雜度和空間複雜度都是O(n)。
解法二:先遍歷一遍求出鏈表長度,計算出鏈表中間節點的位置。然後遍歷前半段,將其反轉。繼續遍歷後半段,將其與反轉後的前半段鏈表逐個比較。時間複雜度是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) {
        ListNode fast = head;// 快指針每次移動兩步
        ListNode slow = head;// 慢指針每次移動一步
        for(; fast != null && fast.next != null; fast = fast.next.next, slow = slow.next);
        //慢指針指向後半段的起始節點,後半段有可能比前半段多一個節點
        ListNode leftStart = head;
        ListNode rightStart = reverseOriginalList(slow);
        
        while(leftStart != slow && leftStart.val == rightStart.val) {
            leftStart = leftStart.next;
            rightStart = rightStart.next;
        }
        return leftStart == slow;
    }
    
    private ListNode reverseOriginalList(ListNode head) {
        ListNode p = null;
        ListNode q = head;
        ListNode r = head == null ? null : head.next;
        while(q != null) {
            q.next = p;
            p = q;
            q = r;
            r = r == null ? null : r.next;
        }
        return p;
    }
    
    // 解法二:先遍歷一遍求出鏈表長度,計算出鏈表中間節點的位置。然後遍歷前半段,將其反轉。繼續遍歷後半段,將其與反轉後的前半段鏈表逐個比較。
    private boolean isPalindromeSolution_2(ListNode head) {
        // count O(n)
        int size = 0;
        ListNode p = head;
        while(p != null) {
            p = p.next;
            size++;
        }
        
        // reverse the left half O(n/2)
        int half = size / 2;
        int i = 0;
        p = null;
        ListNode q = head;
        ListNode r = head == null ? null : head.next;
        while(i++ < half) {
            q.next = p;
            p = q;
            q = r;
            r = r == null ? null : r.next;
        }
        
        // compare O(n/2)
        ListNode leftStart = p;
        ListNode rightStart = size % 2 == 0 ? q : r;
        while(leftStart != null && leftStart.val == rightStart.val) {
            leftStart = leftStart.next;
            rightStart = rightStart.next;
        }
        return leftStart == null;
        // total O(n) 空間複雜度O(1)
    }
    
    // 解法一:將輸入反轉得到一個新的鏈表,逐個比較。時間和空間複雜度都是O(n)
    private boolean isPalindromeSolution_1(ListNode head) {
        ListNode reverseHead = reverseNewList(head);
        while(head != null && head.val == reverseHead.val) {
            head = head.next;
            reverseHead = reverseHead.next;

        }
        return head == null;
    }
    

    private ListNode reverseNewList(ListNode head) {
        ListNode p = null;
        while(head != null) {
            ListNode node = new ListNode(head.val);
            node.next = p;
            p = node;
            head = head.next;
        }
        return p;
        
    }
    
    private void print(ListNode head) {
        StringBuilder sb = new StringBuilder();
        while(head != null) {
            sb.append(head.val);
            head = head.next;
        }
        System.out.println(sb.toString());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章