1. 程式人生 > 實用技巧 >力扣 - 92. 反轉連結串列II

力扣 - 92. 反轉連結串列II

目錄

題目

92. 反轉連結串列 II

思路1(迭代)

  • 將反轉連結串列分成3個部分:前一段未反轉的部分、待反轉連結串列部分、後一段未反轉部分
  • 將3個片段分離後,然後再連線起來
  • 細節注意:如果是從第一個開始反轉連結串列,即前一段未反轉的部分不存在,那麼返回的結果就直接是反轉連結串列片段的新節點,否則就是head

程式碼

class Solution {
    public ListNode reverseBetween(ListNode head, int m, int n) {
        if (head == null) {
            return null;
        }

        // cur用於記錄當前節點的指向,剛開始就是指向head
        ListNode cur = head;
        // prev用於記錄 前一段未反轉的部分 的最後一個節點,預設初始指向null
        ListNode prev = null;
        // 反轉連結串列後的頭結點
        ListNode tail = null;
        // 用於記錄表反轉之後的最後一個節點
        ListNode reverseTail = null;

        // 先獲取prev,遍歷結束後cur指向的是 待反轉連結串列部分 的起使位置
        for (int i = 1; i < m; i++) {
            prev = cur;
            cur = cur.next;
        }
        
        // 待反轉連結串列部分 的起使位置也就是連結串列反轉之後的最後一個節點,我們先記錄下來,為了最後和 後一段未反轉部分 連線起來
        reverseTail = cur;

        // 開始反轉連結串列,遍歷次數要是n-m+1,這樣才能反轉全,那麼此時cur指向的就是 後一段未反轉部分 的起始位置
        for (int i = 0; i < n-m+1; i++) {
            ListNode next = cur.next;
            cur.next = tail;
            tail = cur;
            cur = next;
        }

        // 現在將 待反轉連結串列部分 的尾節點與 後一段未反轉部分 的起始節點連線起來
        reverseTail.next = cur;

        // 判斷 前一段未反轉的部分 的最後一個節點是否為空,如果為空的話,說明反轉的是該連結串列前n個節點,直接返回 反轉鏈後的頭結點
        if (prev == null) {
            return tail;
        } else { 
            // 否則的話,將 前一段未反轉的部分 的最後一個節點與 待反轉連結串列部分 的頭節點連線起來,然後返回head
            prev.next = tail;
            return head;
        }
    }
}

複雜度分析

  • 時間複雜度:\(O(N)\)
  • 空間複雜度:\(O(1)\)

思路2(遞迴)

  • 我們可以遞迴實現反轉連結串列
  • 然後難度再加深一點,實現反轉前 n 個連結串列
  • 但是題目需求是還有前 m-1 個連結串列節點不需要反轉,所以我們通過遞迴把前 m-1 個個省略跳過即可(遞迴時候m和n都要同時減1,這樣才能保證反轉的部分保持不變),當 m 減少為1時,反轉前n個即可
  • 在 reverseN 中,我們需要一個tail來記錄後一部分不反轉連結串列的第一個節點,也是反轉連結串列最後一個節點指向的地方:head.next = tail;

程式碼

class Solution {
    public ListNode reverseBetween(ListNode head, int m, int n) {
        // m為1代表就是直接反轉前n個節點
        if (m == 1) {
            return reverseN(head, n);
        }

        head.next = reverseBetween(head.next, m-1, n-1);
        return head;
    }

    /**
    * 用於記錄反轉連結串列部分的尾結點指向
    */
    ListNode tail = null;

    /**
    * 反轉連結串列的前n個節點
    */
    public ListNode reverseN(ListNode head, int n) {
        if (n == 1) {
            tail = head.next;
            return head;
        }

        ListNode p = reverseN(head.next, n-1);
        head.next.next = head;
        head.next = tail;
        return p;
    }
}

複雜度分析

  • 時間複雜度:\(O(N)\)
  • 空間複雜度:\(O(N)\)