[leetcode] K 個一組翻轉鏈表

題目:25. K 個一組翻轉鏈表node

先看怎麼反轉鏈表(寫不出來的話,我建議你爪巴):函數

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (head == nullptr) return nullptr;
        auto pre = head, cur = head->next;
        while (cur != nullptr)
        {
            auto next = cur->next;
            cur->next = pre;
            pre = cur, cur = next;
        }
        head->next = nullptr;
        return pre;
    }
};

第一步,實現一個 K 個反轉的函數,把 [head, tail] 區間內的節點反轉(與上面的反轉鏈表一毛同樣),返回子鏈表的新的頭和尾code

pair<ListNode*, ListNode*> helper(ListNode* const head, ListNode* const tail)
{
    auto pre = head, cur = head->next;
    auto end = tail->next;
    while (cur != end)
    {
        auto next = cur->next;
        cur->next = pre;
        pre = cur, cur = next;
    }
    head->next = end;
    return {tail, head};
}

第二步,咱們先看看一個例子。leetcode

K = 3, list = [1 2 3 4 5 6]

// 添加一個 dummy 節點
-1 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6
    
// 變量指向
pre  head      tail next
 |    |         |    |
 V    V         V    V
-1    1 -> 2 -> 3    4 -> 5 -> 6

// 執行 (head, tail) = helper(head, tail) 後
pre  head      tail next
 |    |         |    |
 V    V         V    V
-1    3 -> 2 -> 1    4 -> 5 -> 6

// 從新「插入」子鏈表
pre  head      tail next
 |    |         |    |
 V    V         V    V
-1 -> 3 -> 2 -> 1 -> 4 -> 5 -> 6

// 而後調整 [head, tail] 區間,繼續執行 helper
               pre  head      tail  next
                |    |         |     |
                V    V         V     V
-1 -> 3 -> 2 -> 1 -> 4 -> 5 -> 6 -> null

而後就能夠寫出主循環了:get

ListNode* reverseKGroup(ListNode* head, int k) 
{
    if (head == nullptr || head->next == nullptr) return head;

    ListNode *dummy = new ListNode(-1);
    dummy->next = head;
    auto pre = dummy;
    while (head != nullptr)
    {
        auto tail = pre;
        for (int i=0; i<k; i++)
        {
            tail = tail->next;
            // 若是不夠 K 個
            if (tail == nullptr) return dummy->next;
        }
        auto next = tail->next;
        tie(head, tail) = helper(head, tail);
        // 「插入」子鏈表
        pre->next = head, tail->next = next;
        // 區間移動
        pre = tail, head = tail->next;
    }
    return dummy->next;
}

👴 以爲這個常數空間的解法太陰間了,本身寫好多細節都會出問題,因此用棧試試。io

這下子代碼就好看得多了。class

class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) 
    {
        ListNode dummy(-1);
        auto cur = &dummy;
        auto p = head;
        while (p)
        {
            vector<ListNode*> buf;
            for (int i=0; i<k && p != nullptr; i++)
                buf.push_back(p), p = p->next;
            // 不足 K 個,直接連上後續的
            if (buf.size() < k)
            {
                cur->next = buf[0];
                break;
            }
            for (int i=buf.size()-1; i>=0; i--)
                cur->next = buf[i], cur = cur->next;
            // 防止出現環,e.g. k=2, list = [1, 2]
            cur->next = nullptr;
        }
        return dummy.next;
    }
};
相關文章
相關標籤/搜索