[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;
    }
};
相关文章
相关标签/搜索