1. 程式人生 > 其它 >每K個一組反轉單鏈表

每K個一組反轉單鏈表

這是laluladong系列學習的一部分。

同步發表於我的個人站點:每K個一組反轉單鏈表

題目:
給你一個連結串列,每 k 個節點一組進行翻轉,請你返回翻轉後的連結串列。
k 是一個正整數,它的值小於或等於連結串列的長度。
如果節點總數不是 k 的整數倍,那麼請將最後剩餘的節點保持原有順序。

labuladong的解法: https://labuladong.gitee.io/algo/2/17/17/
leetcode官方解法: https://leetcode-cn.com/problems/reverse-nodes-in-k-group/

我把兩種解法的程式碼實現都寫在下面的程式碼裡面了。

關於兩個教程的一些比較:

  1. labuladong的教程相對於leetcode來說更容易理解
  2. labuladong的教程說是迭代解法,但實際上還是用到了遞迴,所以在效能上要比leetcode的解法差一些
  3. leetcode的解題思路更具有引導的作用,比如在head節點前面認為創造一個pre節點可以避免特判,雖然labuladong也是這麼做的,但是沒有明說出來,新手可能不容日get到那個點

整體上來說,建議先看labuladong的教程,實際把程式碼實現一邊,然後再好好看看leetcode官方解法,尤其是解題思路。

leetcode解法中反轉部分子連結串列的地方關於prev節點的處理方法有一點還沒理解,在程式碼中做了註釋,如果有了解的大神希望可以通過評論指導我一下

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

class Solution:
    ## laluladong 解法(迭代)
    # def reverse(self, head: ListNode, tail: ListNode) -> ListNode:
    #     pre = None
    #     cur = head
    #     nxt = head
    #     while cur != tail:
    #         nxt = cur.next
    #         cur.next = pre
    #         pre = cur
    #         cur = nxt
    #     return pre

    # def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
    #     if head == None:
    #         return head
    #     a = head
    #     b = head
    #     for item in range(k):
    #         if b != None:
    #             b = b.next
    #         else:
    #             return head
    #     newHead = self.reverse(a, b)
    #     a.next = self.reverseKGroup(b, k)
    #     return newHead

    ## 官方解法
    # 翻轉一個子連結串列,並且返回新的頭與尾
    def reverse(self, head: ListNode, tail: ListNode):
        prev = tail.next  # 這裡給prev賦值為None也可以,不影響結果,但是效能會差,為什麼?
        p = head
        while prev != tail:
            nex = p.next
            p.next = prev
            prev = p
            p = nex
        return tail, head

    def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
        hair = ListNode(0)
        hair.next = head
        pre = hair

        while head:  # 這個迴圈會反轉整個連結串列,替代了laluladong迭代解法中的遞迴呼叫
            tail = pre
            # 檢視剩餘部分長度是否大於等於 k
            for i in range(k):
                tail = tail.next
                if not tail:
                    return hair.next
            nex = tail.next
            head, tail = self.reverse(head, tail)
            # 把子連結串列重新接回原連結串列
            pre.next = head
            tail.next = nex
            pre = tail  # 此時的tail是後面一段子連結串列的hair(也就是pre)
            head = tail.next
        
        return hair.next