1. 程式人生 > 實用技巧 >迴文連結串列

迴文連結串列

1.問題描述

請判斷一個連結串列是否為迴文連結串列。

示例 1:

輸入: 1->2
輸出: false

示例 2:

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

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

2.求解

儲存到陣列中使用雙指標判斷

  • 遍歷整個連結串列把所有的值儲存到list集合中
  • 設定指標i,j分別從頭部和尾部對比是否相同

程式碼如下

/*
 *執執行用時:4 ms, 在所有 Java 提交中擊敗了28.12% 的使用者
 * 記憶體消耗:42.2 MB, 在所有 Java 提交中擊敗了40.65% 的使用者
 * */
public boolean isPalindrome(ListNode head) {
    if (head == null) {
        return true;
    }
    List<Integer> list = new ArrayList<>();
    while (head != null) {
        list.add(head.val);
        head = head.next;
    }
    int i = 0, j = list.size() - 1;
    while (i < j) {
        if (!list.get(i).equals(list.get(j))) {
            return false;
        }
        i++;
        j--;
    }
    return true;
}
  • 當然在這裡用list陣列只是一種方法,也可以使用棧這一結構來進行比較

遞迴

遞迴比較難以理解,可以先借助下面這個例子理解,如何使用遞迴倒序列印一個連結串列

程式碼如下

public class Solution {
    int i = 0;
    void printNode(ListNode head){
        if(head == null){
            return;
        }
        printNode(head.next);
        i++;
        System.out.println("我是倒數第" + i + "個節點,我的值是:" + head.val);
    }
}
  • 在這段程式碼中,我們把自增的i換成我們需要比較的節點就可以求出題目的答案

程式碼如下

/*
 * 執行用時:3 ms, 在所有 Java 提交中擊敗了33.88% 的使用者
 * 記憶體消耗:44.5 MB, 在所有 Java 提交中擊敗了5.00% 的使用者
 * */
ListNode temp;
public boolean isPalindrome2(ListNode head) {
    temp = head;
    return check(head);
}

public boolean check(ListNode head) {
    if (head == null) {
        return true;
    }
    boolean ans = (check(head.next) && head.val == temp.val);
    temp = temp.next;
    return ans;
}
  • 在方法外面定義全域性變數temp,這個temp相當於我們上文中的i
  • 遞的過程先拿到連結串列的最後一個節點,然後開始歸的過程,用最後一個節點與temp比較,用倒數第二個節點與temp.next比較,以此類推

反轉連結串列後半部分

在方法1和方法2中我們無論如何都做不到O(1)的空間複雜度,要想滿足O(1)的空間複雜度,我們可以使用反轉後半部分連結串列來對比的方法

程式碼如下

/*
 * 執行用時:1 ms, 在所有 Java 提交中擊敗了99.86% 的使用者
 * 記憶體消耗:40.9 MB, 在所有 Java 提交中擊敗了96.45% 的使用者
 * */
public boolean isPalindrome3(ListNode head) {
    ListNode fast = head, slow = head;
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
    }
    if (fast != null) {
        slow = slow.next;
    }
    slow = reverse(slow);
    while (slow != null) {
        if (slow.val != head.val) {
            return false;
        }
        slow = slow.next;
        head = head.next;
    }
    return true;
}

ListNode reverse(ListNode head) {
    ListNode pre = null;
    ListNode curr = head;
    while (curr != null) {
        ListNode temp = curr.next;
        curr.next = pre;
        pre = curr;
        curr = temp;
    }
    return pre;
}

ps:如何使用遞迴反轉連結串列
劍指 Offer-反轉連結串列的3種方式