K个一组反转链表

链表如下: head -> 1, tail -> 8
1 -> 2 -> 3 -> 4 ->5 -> 6 -> 7 -> 8-> nullptr

K = 3
=> 
1 -> 2 -> 5 -> 4 -> 3 -> 8 -> 7 -> 6 -> nullptr
(最后一部分小于K, 则不用再反转)

K = 4
=>
4 -> 3 -> 2 -> 1 -> 8 -> 7 -> 6 -> 5 -> nullptr
(head和tail都发生了变化)

  • 接到题目先明确1, 2个具体的例子, e.g. 如上; 尽量在前面搞清需要留意的大部分乃至所有细节, 例如以上的K=4时, head是会发生改变的;
  • 基本思路分析:
    • 此题很容易想到是基本的递归方法, 由于是逆序反转, 则应该是"递"的过程走到最后的节点(current == tail), 然后开始反转,首先状态参数应该是有前一个节点; 再者, 由于是K个一组,所以需要往递归实现的函数里塞入当前链表节点的索引计数idx, 在"归"的过程中, 想办法通过这个idx计算出当前节点是否达到第K个了; 如果是非递归手工栈实现, 则这些一般是要入栈的信息;
    • 计数是否K个一组的办法是, 在tail处用idx和K做模得到offset, 那么向前移动K步, 计数的条件是下一个节点的idx % k == offset + 1的位置, 即满足一组;
    • idx % K == offset + 1的节点, 不能再指向前一个节点, 而是指向下一组的第一个节点; 所以在"归"的过程中还需要做一些标记任务:
      • 在每一组开始的第一个节点(idx % k == offset)的时候, 需要标记当前节点是下一组k个元素的头节点需要指向的元素(next_pre_group_last);
      • 在每一组的最后一个节点(idx % K == offset + 1)时, 把当前节点指向前一组的第一个节点(pre_group_last), 更新pre_group_last的值为next_pre_group_last;
      • tail节点, 标记pre_group_last为tail-next (nullptr), next_pre_group_last为tail;
  • 递归函数的状态参数:
    • head, tail, 是链表头尾;
    • curr, prev是链表的当前和上一个, 为了在"归"的过程中设定反转;
    • K, idx: 分别是K和当前链表节点的计数索引;
  • 注意, head的指向可能是会发生改变的; 当K个一组, 恰好消耗完整个链表, head应该指向第一组的末尾节点; 所以递归状态的返回值应该非void而是struct Node* head;
#include <iostream>
#include <algorithm>
using namespace std;

struct Node {
    int val;
    struct Node* next;
};

struct Node* reverseLinkList(struct Node* head, struct Node* tail,
    struct Node* prev, struct Node* curr, int k, int idx) {
        static int offset  = 0;
        static bool back = false;
        static struct Node* pre_group_last = nullptr;
        static struct Node* next_pre_group_last = nullptr;

        if (curr != tail && back != true) {
            reverseLinkList(head, tail, curr, curr->next, k, ++idx);
        }

        if (curr == tail) {
            back = true;
            offset = idx % k;
            pre_group_last = tail->next;
            next_pre_group_last = tail;
            tail->next = prev;
            return curr;
        }

        int j = idx - 1;

        bool b_section_end = j % k == (offset + 1) % k;
        bool b_first_section = j < k - offset;
        if (!b_section_end && !b_first_section) {
            curr->next = prev;
        }

        if (b_section_end) {
            curr->next = pre_group_last;
            pre_group_last = next_pre_group_last;
            if (b_first_section) {
              head = next_pre_group_last;
            }
        }

        if (j % k == offset) {
            next_pre_group_last = curr;
        }

        return head;
}

std::pair<struct Node*, struct Node*> makeLinkedList() {
  struct Node* tail = new Node{8, nullptr};
  struct Node* n7 = new Node{7, tail};
  struct Node* n6 = new Node{6, n7};
  struct Node* n5 = new Node{5, n6};
  struct Node* n4 = new Node{4, n5};
  struct Node* n3 = new Node{3, n4};
  struct Node* n2 = new Node{2, n3};
  struct Node* head = new Node{1, n2};

  return std::make_pair(head, tail);
};

int main() {
    int k[] = {2, 3, 4, 5};

    std::for_each(begin(k), end(k), [&](int i) {
        pair<struct Node*, struct Node*> list = makeLinkedList();
        cout << "K =" << i << endl;
        cout << "before reverse: " << endl;
        for (struct Node* p = list.first; p != nullptr; p = p->next)
            cout << p->val << ", ";
        cout << endl;

        struct Node* head = reverseLinkList(list.first, list.second, nullptr, list.first, i, 0);
        cout << "after reverse: " << endl;
        for (struct Node* p = head; p != nullptr; p = p->next) {
            cout << p->val << ", ";
        }
        cout << endl;
    });
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值