写点什么

算法题学习 --- 链表中的节点每 k 个一组

作者:桑榆
  • 2022-11-07
    广东
  • 本文字数:1572 字

    阅读完需:约 5 分钟

题目

描述

将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表 如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样 你不能更改节点中的值,只能更改节点本身。

数据范围: 0≤n≤2000 ,1≤k≤2000 ,链表中每个元素都满足 0≤val≤1000 要求空间复杂度 O(1),时间复杂度 O(n)

例如:

给定的链表是 1→2→3→4→5

对于 k = 2 , 你应该返回 2→1→4→3→5

对于 k = 3 , 你应该返回 3→2→1→4→5

示例 1

输入:{1,2,3,4,5},2返回值:{2,1,4,3,5}
复制代码

示例 2

输入:{},1返回值:{}
复制代码

分析

考虑特殊情况

在进行问题分析过程前,我们先考虑一下特殊情况,那么在这道问题中,有哪些情况是特殊的呢?

不难发现,如下两种情况:

  • 空链表,即头指针为 NULL,这种情况我们直接返回头指针即可;

  • 链表只有一个节点,即 pHead->next 为 NULL,这种情况我们也直接返回头指针即可。

  • 如果 k<=1,说明并不需要进行链表反转,直接返回头指针即可

考虑一般情况

这里我们看一下问题的一般形式,也即是对中间的每一组链表进行逆序,这个的方法其实在我们之前的问题中已经出现过了https://xie.infoq.cn/article/5066d80a910ae4b753b9a4751 ,所以这里我们就将问题做一下拆解:

  • 找出当前需要进行逆序的子链表,确定该子链表的 pPre 和 pEnd;

  • 对 pPre 到 pEnd 中间的节点进行区间逆序算法;

  • 更新 pPre 和 pEnd 到下一个子链表,直到无法找到满足条件的子链表。

注意,这里我们也同样使用一个虚拟 node 来指向我们的头结点,避免对头结点做判断导致的逻辑复杂。

代码示例

注意:如下的代码示例中

  • pReturn 是我们的返回节点,它指向头结点;

  • pPre 是每一个子链表的头结点的前驱节点,开始时初始化为 pReturn,完成子链表逆序之后被更新为 pCur 的值,在子链表逆序过程中不发生改变;

  • pCur 是子链表中当前指向的节点,在逆序完成后(即 pNext 节点被插入 pPre 后面之后)指向下一个子链表的第一个元素,也即是下一个子链表头节点的前驱节点;

  • pNext 是 pCur 的下一个元素,如果不等于 pEnd,那就需要逆序插入到 pPre 后面;

  • pEnd 是子链表的尾节点。

还有一点,如果我们在寻找 pEnd 节点的过程中遍历到了链表末尾,那说明最后的这一组不需要做子链表逆序,直接返回 pReturn->next 即可。

/** * struct ListNode { *  int val; *  struct ListNode *next; * }; */
class Solution { public: /** * * @param head ListNode类 * @param k int整型 * @return ListNode类 */ ListNode* reverseKGroup(ListNode* head, int k) { // write code here if (nullptr == head || nullptr == head->next || k <= 1) { return head; }
ListNode* pReturn = static_cast<ListNode*>(malloc(sizeof(ListNode))); pReturn->val = -1; pReturn->next = head;
ListNode* pPre = nullptr; ListNode* pCur = nullptr; ListNode* pNext = nullptr; ListNode* pEnd = nullptr;
pPre = pReturn; while (nullptr != pPre) { pEnd = pPre; for (int i = 0; i < k; ++i) { pEnd = pEnd->next; if (nullptr == pEnd) { // no need reverse for this seg list return pReturn->next; } }
// reverse sublist until to the pEnd pCur = pPre->next; while (pNext != pEnd) { pNext = pCur->next; pCur->next = pNext->next; pNext->next = pPre->next; pPre->next = pNext; }
// assign the pPre pPre = pCur; } return pReturn->next; }};
复制代码


发布于: 刚刚阅读数: 4
用户头像

桑榆

关注

北海虽赊,扶摇可接;东隅已逝,桑榆非晚! 2020-02-29 加入

Android手机厂商-相机软件系统工程师 爬山/徒步/Coding

评论

发布
暂无评论
算法题学习---链表中的节点每k个一组_算法题_桑榆_InfoQ写作社区