0092. Reverse Linked List II - chasel2361/leetcode GitHub Wiki

Reverse a linked list from position m to n. Do it in one-pass.
Note: 1 ≤ m ≤ n ≤ length of list.

Example:
Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 1->4->3->2->5->NULL

這個題目的重點在於如何將單向串接的串列在指定的位置反向連接,我自己試了一下,主要概念是把需要轉向的部分用一個 list 存起來,需要的時候再拿出來用。有寫出符合例題的狀況,但如果把 m, n 改掉就會失敗,所以決定參考雨蕭大大的寫法。

他的想法跟我類似,但又更精細一點,除了利用 stack: [list] 把需要轉向部分存起來之外,還多了一個 left 值儲存 m 的前一個位置,以方便後續連接。

stack 這種資料結構的特性是後進先出,在 python 中可以用 list 的形式實現,輸入時使用 list.append() ;提出時使用 list.pop()。

反轉的部分可以使用 list.pop() 的函式,它會自動取出最後一個值並刪除。但這只有解決取出順序的問題,反向串接需要使用兩個變數,先令 l1 = stack.pop(), l2 = None,再進入迴圈,裡面先把 l2 指向 stack.pop(),接著把 l1.next 指向 l2 得到第一個反向連接、再把 l1 指向 l2 清出一個下一個 stack.pop() 的空間 ( 每次 l1 所在的位置,都是當前準備進行連接 next 的節點 ) ,直到 stack 不存在為止,便完成反向連接。

另外還需要考慮 m = 1 的狀況,此時需要將 head 指向 l1 ,也就是第一個開始反向連接的節點

由此可以得出以下程式碼:

[1] 若 m = n 就不需要反轉,直接回傳 head
[2] 當 node 移動到 m, n 之間時,使用 stack 來儲存這些需要反轉的節點
[3] 當 m = 1 時,需要將 head 指向 l1 ,變更起始節點
[4] 當 m != 1 時,將 l1 接到 left.next
[5] 反向連接結束後,需要接回 node ,結束動作

class Solution:
    def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
        if m == n: return head  # [1]
            
        stack = []
        left, node = None, head
            
        if m != 1:
            for _ in range(1, m - 1):
                node = node.next
            left = node
            node = node.next
            
        for _ in range(m, n + 1):
            stack.append(node)  # [2]
            node = node.next
            
        l1, l2 = stack.pop(), None
        if m == 1:
            head = l1  # [3]
        else:
            left.next = l1  # [4]
        
        while stack:
            l2 = stack.pop()
            l1.next = l2
            l1 = l2
        l1.next = node  # [5]
        return head

這樣寫的時間複雜度是 O(N),空間複雜度是 O(N)

Code Link