当前位置:   article > 正文

LeetCode 25.k个一组翻转链表(Reverse Nodes in k-Group)

给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。k 是一个正整数,它的

16846478-3ce5a2f42859cca9.jpg

LeetCode.jpg

 

k个一组翻转链表

给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。

示例 :

给定这个链表:1->2->3->4->5

当 k = 2 时,应当返回: 2->1->4->3->5

当 k = 3 时,应当返回: 3->2->1->4->5

说明 :

你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

切题

一、Clarification

1、每组k个元素翻转后,每组之间的衔接。[1,k] 与 [k+1,2k]之间衔接

2、注意 剩余元素的处理

二、Possible Solution

1、迭代

遍历链表 找出每组的 首尾以及下一组的首,借助单链表翻转获得翻转后的首尾,对首尾节点衔接处理,对哨兵节点移位处理

时间复杂度 O(N)

2、递归

递归终止条件:

剩余节点 < k

递归从里向外出来,每层递归返回当前层级链表翻转后的头节点,那么每层递归中我们知道当前层级翻转后的头尾节点以及下一个k元素组的头节点(递归的上一层级),可以很轻松地将翻转后的链表衔接起来

3、借助栈

将k个元素压入栈,通过出栈翻转,注意剩余元素处理

Python3实现

迭代 借助单链表翻转

  1. # @author:leacoder
  2. # @des: 迭代 借助单链表翻转 k个一组翻转链表
  3. class Solution:
  4. def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
  5. cur = head #由于遍历
  6. dim = ListNode(0) #新建一节点
  7. dim.next = head #next指向head
  8. pre = dim #pre 赋值为 dim 1、记录和获取 k个一组的头 2、方便统一处理
  9. # pre 与 dim 均为哨兵
  10. count = 1
  11. while cur: #遍历链表
  12. if count % k == 0: #k个一组 对这里面的数据翻转
  13. nextstart = cur.next #记录 后一个 k个一组的 头节点
  14. cur.next = None #赋值为None 前面 k个一组数据 为新的链表 以 None结束 这个新链表可以采用206的处理方式
  15. end, start = self.reverse(pre.next) #翻转新链表 返回翻转的 尾 和 头 注pre.next 为新链表翻转前的头
  16. # 衔接处理,哨兵的next指向翻转后的头, 翻转后的尾的next指向nextstart
  17. # pre 和 cur 依次下移k个元素 变为 end 和 nextstart下一轮处理就变成本轮一样了
  18. pre.next,end.next,pre,cur = start,nextstart,end,nextstart
  19. else:
  20. cur = cur.next #我们关心k个一组的首尾
  21. count += 1
  22. return dim.next
  23. def reverse(self, head): #翻转链表
  24. dim1,cur,pre = head,head,None
  25. while cur: #遍历
  26. cur.next,pre,cur = pre,cur,cur.next
  27. return dim1,pre #翻转后endstart

递归

  1. # @author:leacoder
  2. # @des: 递归 k个一组翻转链表
  3. class Solution:
  4. def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
  5. if self.isEnd(head,k):
  6. return head
  7. pre = ListNode(None) # 哨兵
  8. pre.next,cur,count = head,head,1
  9. while count <= k: # 翻转 k个元素链表 处理类似 206
  10. cur.next,pre,cur,count = pre,cur,cur.next,count + 1
  11. # 循环结束后 cur 指向 下一组 k个元素(未翻转)的头 ;pre指向当前组在翻转后的头节点
  12. nexthead = self.reverseKGroup(cur,k) # nexthead 下一组翻转后的头节点
  13. head.next = nexthead #当前组的head在翻转后成为尾节点,其next指向nexthead 下一组翻转后的头节点
  14. return pre # 返回 翻转后的头节点
  15. # 递归终止判断:
  16. def isEnd(self,head,k):
  17. count,cur = 0,head
  18. while cur:
  19. count = count + 1
  20. cur = cur.next
  21. if count >= k:
  22. return False #
  23. return True

借助栈

  1. # @author:leacoder
  2. # @des: 借助栈 k个一组翻转链表
  3. class Solution:
  4. def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
  5. result= ListNode(None)
  6. cur,result.next = head,head
  7. tmpresult = result
  8. stack = [] # 列表实现栈的 先入后出功能
  9. count = 0
  10. while cur:
  11. count = count + 1
  12. stack.append(cur) # 入栈
  13. cur = cur.next
  14. if count % k == 0: # 已存储k个元素
  15. count = 0
  16. while stack: # 出栈倒换
  17. tmpresult.next = stack.pop()
  18. tmpresult = tmpresult.next
  19. # 处理 stack 中剩余元素
  20. while stack:
  21. tmpresult.next = stack.pop(0) #
  22. tmpresult = tmpresult.next
  23. return result.next

C++实现

存储法

用数组存储k个元素,虽然能通过但是执行用时有点长,不过逻辑简单

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode(int x) : val(x), next(NULL) {}
  7. * };
  8. * @author:leacoder
  9. * @des: 存储法 k个一组翻转链表
  10. */
  11. class Solution {
  12. public:
  13. ListNode* reverseKGroup(ListNode* head, int k) {
  14. ListNode *nodearray[k];//存储 需翻转的 k个节点
  15. ListNode* result = new ListNode(0); //翻转后链表 用于结果返回
  16. ListNode* ret = result;//由于存储翻转后链表
  17. int count = 0;
  18. while( NULL != head){
  19. ListNode* next = head->next; //记录下移节点
  20. nodearray[count] = head; //记录到数组
  21. count++;//数组 下标自加
  22. if(k == count){ //已存 k个值 需要翻转了
  23. for(int i = k;i>0;i--){ //循环读取 数组中数据
  24. ret->next = nodearray[i-1]; //从后往前去数组中数据 添加到ret链表中
  25. ret = ret->next;//移位
  26. nodearray[i-1] = NULL;//置空
  27. count--;//数组中数据个数--
  28. }
  29. }
  30. head = next;
  31. }
  32. for(int i = 0;i<count;i++){//处理不需要翻转的数据
  33. ret->next = nodearray[i];
  34. ret = ret->next;
  35. nodearray[i] = NULL;
  36. }
  37. ret->next = NULL;
  38. return result->next;
  39. }
  40. };

k作为函数参数传入后就确定了可以当做常数,但是k作为参数可以为合理范围内任意值不确定,这点和题目描述说明貌似有点出入
说明 : 你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

我这种方法处理也只是提供一种思路,待后续其他实现方法


GitHub链接:
https://github.com/lichangke/LeetCode

知乎个人首页:
https://www.zhihu.com/people/lichangke/

简书个人首页:
https://www.jianshu.com/u/3e95c7555dc7

个人Blog:
https://lichangke.github.io/

欢迎大家来一起交流学习

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/86900
推荐阅读
相关标签
  

闽ICP备14008679号