31.K 个一组翻转链表
给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例 1:

输入:head = [1,2,3,4,5], k = 2 输出:[2,1,4,3,5]
步骤分解:
链表分区为已翻转部分+待翻转部分+未翻转部分
每次翻转前,要确定翻转链表的范围,这个必须通过 k 此循环来确定
需记录翻转链表前驱和后继,方便翻转完成后把已翻转部分和未翻转部分连接起来
初始需要两个变量 pre 和 end,pre 代表待翻转链表的前驱,end 代表待翻转链表的末尾
经过k此循环,end 到达末尾,记录待翻转链表的后继 next = end.next
翻转链表,然后将三部分链表连接起来,然后重置 pre 和 end 指针,然后进入下一次循环
特殊情况,当翻转部分长度不足 k 时,在定位 end 完成后,end==null,已经到达末尾,说明题目已完成,直接返回即可

【对着图像看代码】
public ListNode reverseKGroup(ListNode head, int k) { ListNode dummy = new ListNode(0); // 此处只是设置一个哨兵节点 dummy.next = head; // 哨兵节点的下一个指向首节点 ListNode pre = dummy; // 上一段的最后一个节点 节点初始化 ListNode end = dummy; // 本段最后一个节点 while (end.next != null) { // 此处是为了找到其中的 k 个子节点 for(int i = 0 ; i < k && end != null; i++){ end = end.next; } if(end == null){ // 如果直接到头了,那就说明没有满足 k 个 break; } ListNode start = pre.next; // 此处是为记录原始未反转段的起始节点 ListNode nextStart = end.next; // 记录下一个阶段 起始点 end.next = null; // 此处是为了进行后面的反转操作,断开此处链接,让后面反转操作知道截断点在哪里 pre.next = reverse(start); // 反转操作 start.next = nextStart; // 反转之后,start节点实际是已经最后一个节点了,为了和后面的划分段链接,让他的下一个节点连接上下一段的起始点即可 pre = start; // pre再次来到下一段的上一个节点,也就是本段的结尾点 end = pre; // 结束点,准备开始下一段的循环找 k 长度的段操作 } return dummy.next; // 返回最开始的哨兵 } private ListNode reverse(ListNode head){ ListNode pre = null; ListNode curr = head; while(curr != null){ // 交换操作 ListNode next = curr.next; curr.next = pre; pre = curr; curr = next; } return pre; // 返回哨兵,此处是新的翻转序列的起始节点 }
作者:房建斌学算法 来源:力扣(LeetCode)

浙公网安备 33010602011771号