【LeetCode234】迴文鏈表

1. 題目

【題目鏈接】👉234. 迴文鏈表

請判斷一個鏈表是否爲迴文鏈表。

示例 1:

輸入: 1->2
輸出: false

示例 2:

輸入: 1->2->2->1
輸出: true

進階:你能否用 O(n) 時間複雜度和 O(1) 空間複雜度解決此題?


2. 鏈表構建

節點的創建連接

  • 先在堆上開闢空間,將待添加的節點放入,new ListNode(node)
  • 然後指針後移一位即可temp = temp.next
    在這裏插入圖片描述

指針移動

  • 將指針cur的值(地址)複製給pre即可
    在這裏插入圖片描述

鏈表複製構建

創建一個 [以head爲頭結點的鏈表] 相同的鏈表(head爲頭結點鏈表的克隆)


3. 解法一:鏈表複製反轉比較

  • 先將給定鏈表複製一份新的res
  • 反轉res
  • 遍歷res和原鏈表,比較val是否相等
class Solution {
    public boolean isPalindrome(ListNode head) {
        if(head == null || head.next == null)   return true;
        ListNode res = new ListNode(head.val);
        ListNode node = res;
        ListNode temp = head.next;
        while(temp != null) {
            node.next = new ListNode(temp.val);
            node = node.next;
            temp = temp.next;
        }
        /*鏈表res克隆完成*/ 
        ListNode l1 = head; //不破壞原鏈表結構,定義指針開始遍歷
        ListNode l2 = reverse(res);
        while(l1 != null) {
            if(l1.val != l2.val) {
                return false;
            }
            l1 = l1.next;
            l2 = l2.next;
        }
        return true;
    }

    public ListNode reverse(ListNode head) {
        if(head == null)    return null;
        ListNode prev = null;
        while(head != null) {
            ListNode next = head.next;
            head.next = prev;
            prev = head;
            head = next;
        }
        return prev;
    }
}

4. 解法二:輔助數組法

  • 單鏈表檢查迴文串的難點就在於,只能沿一個方便遍歷,雙指針無法進行

  • 於是我們就想到可以借用一個輔助數組,將鏈表節點拷貝到數組中,然後再數組中雙指針檢查,非常容易!

在這裏插入圖片描述

題解圖片來自@海底的🐟【原文題解】

class Solution {
    public boolean isPalindrome(ListNode head) {
        if(head == null || head.next == null)   return true;
        ArrayList<Integer> list = new ArrayList<>();
        ListNode temp = head;
        while(temp != null) {
            list.add(temp.val);
            temp = temp.next;
        }
        int left = 0;
        int right = list.size() - 1;
        while(left <= right) {
            if(!list.get(left).equals(list.get(right)))
                return false;
            left++;
            right--;
        }
        return true;
    }
}

5. 解法三:快慢指針 + 折半反轉

  • 你能否用 O(n) 時間複雜度和 O(1) 空間複雜度解決此題
class Solution {
    public boolean isPalindrome(ListNode head) {
        if(head == null || head.next == null)   return true;
        ListNode slow = head;
        ListNode fast = head.next;
        //快慢指針不斷迭代,找到中間節點
        while(fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        // 偶數節點,讓 slow 指向下一個節點
        if(fast != null) {
            slow = slow.next;
        }
        // 切成兩個鏈表
        cut(head, slow);                     
        return isEqual(head, reverse(slow));
    }

    private void cut(ListNode head, ListNode cutNode) {
        while (head.next != cutNode) {
            head = head.next;
        }
        head.next = null;
    }

    private ListNode reverse(ListNode head) {
        if(head == null)    return head;
        ListNode prev = null;
        while(head != null) {
            ListNode next = head.next;
            head.next = prev;
            prev = head;
            head = next;
        }
        return prev;
    }

    private boolean isEqual(ListNode l1, ListNode l2) {
        while (l1 != null && l2 != null) {
            if (l1.val != l2.val) return false;
            l1 = l1.next;
            l2 = l2.next;
        }
        return true;
    }
}

如果兩表元素爲偶數個時,切割完後:

  • L1:1 —> 2 —> null
  • L2:1—> 2 —> 3 —> null

isEqual方法的條件是l1 != null && l2 != null,L1走到節點2後爲空,結束循環!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章