题目描述
解题思路
这题乍一看好像就是 24. 两两交换链表中的节点 - 力扣(LeetCode) (leetcode-cn.com) (opens new window)的升级版,但是你要还是用迭代法,那指针的顺序能把你搞疯。
所以最佳方案是递归,因为翻转 k 个节点的操作是一样的,不同点就在于,每一段的起始节点不同罢了。我们把翻转 k 个节点的方法提取出来,然后不断地去调用它,每调用完一次,就更新下一段起始节点。
以下图片配合代码使用,保证能懂!!!:
1)先反转前 k 个 [head, tail), 得到的头节点就是最终链表的头节点
2)递归调用反转后续的链表
package com.kami.leetcode.list_study;
import com.kami.leetcode.list_study.listNode.ListNode;
/**
* @Description: TODO
* @author: scott
* @date: 2021年12月24日 9:26
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
public class Solution_25 {
public ListNode reverseKGroup(ListNode head, int k){
if(head == null || head.next == null){
return head;
}
// 找到第 k + 1 个节点(作为进入第一段递归调用的末尾节点)
ListNode tail = head;
for(int i = 0; i < k; i++){
if(tail == null){
//链表个数不足k个
return head;
}
tail = tail.next;
}
// 先反转前 k 个 [head, tail), 得到的头节点就是最终链表的头节点
ListNode newHead = reverse(head, tail);
//递归调用反转后续的链表
head.next = reverseKGroup(tail, k);
return newHead;
}
// 原地反转从 head 到 tail(不包含 tail) 的链表
private ListNode reverse(ListNode head, ListNode tail){
ListNode cur = head;
ListNode pre = null;
// 保存 cur = 后继节点
ListNode successor;
while (cur != tail){
successor = cur.next;
//更改next指向
cur.next = pre;
// 进入下一个节点
pre = cur;
cur = successor;
}
// 反转之后, head 仍指向原来那个元素,pre 指向新的第一个元素)
// 返回反转后链表的头节点
return pre;
}
}