25. K 个一组翻转链表 + 链表的翻转
25. K 个一组翻转链表
25. K 个一组翻转链表
题目描述
题解分析
- 这题的主要解决思路就是链表的翻转,关键是要找到每次翻转的头结点和尾结点。
- 外层是一个while(true)循环,内存找到本次需要翻转的k个结点的左右边界。
代码实现
解法一:迭代法
/**
* 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; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dumyHead = new ListNode(0);//创建虚拟头结点
dumyHead.next = head;
ListNode pre = dumyHead;
while(head != null){
ListNode temp = pre;
for(int i=0; i<k; i++){//判断剩下的链表是否够k个结点
temp = temp.next;
if(temp == null)
return dumyHead.next;//直接返回链表
}
ListNode next = temp.next;
ListNode[] res = reverseLink(head, temp);
head = res[0];//头结点
temp = res[1];//尾结点
pre.next = head;
temp.next = next;
pre = temp;
head = temp.next;//新的头结点
}
return dumyHead.next;
}
/*
翻转头结点和尾结点之间的这段链表
*/
public ListNode[] reverseLink(ListNode head, ListNode tail){
ListNode pre = tail.next;//这里很关键,前置结点设置为尾结点的下一个结点
ListNode current = head;
while(pre != tail){//注意这里是pre不等于尾结点
ListNode temp = current.next;
current.next = pre;
pre = current;
current = temp;
}
return new ListNode[]{tail, head};
}
}
解法二:递归法
- 与反转链表题目类似,本题也可以使用递归法来实现,只不过实现的步骤稍微有些麻烦。
- 递归方法中,每次返回的是子递归的新头节点newHead,在递归之后,需要将当前头节点head的next指针指向子递归的头节点。
- 需要注意的是,在递归边界中,如果遇到了head为null或者head.next为null,都需要返回head表示无法翻转空节点或者单个节点。
/**
* 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; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if(head == null || head.next == null){
return head;
}
ListNode tail = head;
for(int i=0; i<k-1; i++){
tail = tail.next;
if(tail == null){
return head;
}
}
ListNode[] temp = reverse(head, tail);
ListNode newHead = temp[0];
head.next = reverseKGroup(temp[1].next, k);
return newHead;
}
private ListNode[] reverse(ListNode slow, ListNode fast){
ListNode pre = fast.next;
ListNode now = slow;
while(pre != fast){
ListNode temp = now.next;
now.next = pre;
pre = now;
now = temp;
}
return new ListNode[]{fast, slow};
}
}
Either Excellent or Rusty
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了