力扣 - 92. 反轉連結串列II
阿新 • • 發佈:2020-12-08
目錄
題目
思路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)\)