題:
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
一般的鏈表翻轉是將整個鏈表翻轉,其圖解方法可以參見:Python劍指offer之反轉鏈表-圖解
這道題的一般解法是:首先要添加一個新的頭節點,這樣可以解決當前頭節點發生變動的情況,這是必備套路;然後將3插入到1和2之間,再將4插入到1和3之間。
1 -> 2 -> 3 -> 4 -> 5 -> NULL
1 -> 3 -> 2 -> 4 -> 5 -> NULL
1 -> 4 -> 3 -> 2 -> 5 -> NULL
在解釋遞歸解法之前,思考一下對數組的翻轉,可以用前後兩個指針,向中間移動,同時交換位置
鏈表的遞歸解法也借用了上面的思路,而且非常巧妙,用了一個trick:用遞歸來實現鏈表的回溯,因爲鏈表不像數組,可以從後往前遍歷,但藉助遞歸,實際也就是棧,可以實現這一操作,下面爲對應的python代碼。
class Solution:
def reverseBetween(self, head, m, n):
if not head:
return None
left, right = head, head
stop = False
def recurseAndReverse(right, m, n):
nonlocal left, stop
if n == 1:
return
right = right.next
if m > 1:
left = left.next
recurseAndReverse(right, m - 1, n - 1)
if left == right or right.next == left:
stop = True
if not stop:
left.val, right.val = right.val, left.val
left = left.next
recurseAndReverse(right, m, n)
return head
代碼中的 nonlocal left, stop 非常關鍵,將 left, stop 設置爲了局部的全局變量,這一就可以在recurseAndReverse函數中改變外部變量left, stop的值,而right是recurseAndReverse函數的內部變量,會在遞歸返回的時候回溯到上一個節點,而left則直接next到下一個節點,實現了和翻轉數組一樣的操作。
既然翻轉鏈表的升級版可以這麼操作,那一般情況就更不在話下了,如下:
def reverse_list(head):
if not head or not head.next:
return head
left, right = head,head
stop = False
def recurseAndReverse(right):
nonlocal left, stop
if not right: return
helper(right.next)
if left == right or right.next == left:
stop = True
if not stop:
left.val, right.val = right.val, left.val
left = left.next
recurseAndReverse(right)
return head