网站首页 > 精选教程 正文
题目
K 个一组翻转链表 * 给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。 * k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 * 输入:head = [1,2,3,4,5], k = 2 * 输出:[2,1,4,3,5]
思路
此解法的主要思想是通过不断寻找并反转每k个一组的子链表来逐步完成整个链表的翻转操作,同时利用哑节点简化边界条件处理,确保整个过程能够正确地处理任何长度和情况的链表。
- 初始化: 创建一个哑节点(dummy node),其next指向原链表头节点。使用两个指针pre和end,初始时都指向哑节点。
- 遍历分组: 使用循环遍历链表,并通过内层循环找到每k个一组的子链表的结束位置(即end)。
- 反转子链表: 当找到包含k个节点的子链表时,记录子链表的开始位置(即start)和子链表结束后紧跟的下一个节点(即next)。 然后,断开子链表与剩余部分的连接,通过递归调用reverse(start)方法反转子链表。
- 恢复连接: 反转后的子链表头部成为新的起始节点,将其连接回原链表剩余部分:start.next = next;同时更新pre指针指向反转后的新起始节点。
- 迭代继续: 更新end指针到新的位置,以便处理下一组节点。
时间复杂度分析
该方法的时间复杂度主要由以下部分组成:
- 查找k个节点的子链表结束位置:通过一个for循环完成,循环次数最多为k次。因此这部分的时间复杂度为O(k)。
反转子链表:在原代码中使用递归的reverse(start)方法,其时间复杂度为O(k),因为需要遍历并翻转整个包含k个节点的子链表。
主循环:在链表中迭代,每次迭代至少处理一组(k个)节点,直到链表末尾。由于链表长度为n,且每次操作一组k个节点,所以总共执行的操作次数大约是n / k次。因此这部分的时间复杂度为O(n/k)。
综合以上分析,该算法总的时间复杂度为O(n + n/k),因为反转每个子链表所需的时间相对于总的链表长度来说是可以忽略不计的,最终我们可以将时间复杂度简化为O(n)。这意味着对于给定的链表长度和分组大小k,算法整体运行时间与链表长度线性相关。
实现代码
public class ReverseKGroup {
public ListNode reverseKGroup(ListNode head, int k) {
// 初始化: 创建一个哑节点(dummy node),其next指向原链表头节点。使用两个指针pre和end,初始时都指向哑节点。
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
ListNode end = dummy;
// 2. 遍历分组: 使用循环遍历链表,并通过内层循环找到每k个一组的子链表的结束位置(即end)。
while (end.next != null) {
// 内层循环用于查找包含k个节点的子链表的结束位置(end)
for (int i = 0; i < k && end != null; i++) {
end = end.next;
}
if (end == null) break;
// 记录当前待反转子链表的起始位置(start)和反转后需要连接的下一个节点(next)
ListNode start = pre.next;
ListNode next = end.next;
end.next = null;
// 反转子链表:调用reverse方法对从start开始的子链表进行翻转,并更新pre.next指向翻转后的子链表头部
pre.next = reverse(start);
start.next = next;
// 更新pre指针,使其指向已反转子链表的新头部,以便在下一次循环中继续处理新的子链表
pre = start;
end = pre;
}
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;
}
}
分析
- 主要难点在于思路, 主要运用了分治和双指针,每k个一组在将链表分为多个组,双指针在于记录起始位置和链表翻转后的连接。
- 最好用图解的方法记录分组后的起始和结束的位置,这样更好理解。
猜你喜欢
- 2024-11-02 LeetCode-025-K 个一组翻转链表 每k个一组翻转链表
- 2024-11-02 C++算法(五)反转链表 反转链表c#
- 2024-11-02 61. 旋转链表 反转链表 头插法
- 2024-11-02 字节面试算法集第三题链表反转 #算法
- 2024-11-02 Java数据结构和算法—链表 java中的链表数据结构
- 2024-11-02 面试现场:如何实现链表的逆序? 链表逆置是什么意思
- 2024-11-02 LeetCode-206-反转链表 反转链表 迭代
- 2024-11-02 迭代法 链表翻转 #软件开发 迭代法程序
- 2024-11-02 每日算法---单链表反转和是否有环
- 2024-11-02 C++:挑战鹅厂面试题(一)--反转链表
你 发表评论:
欢迎- 04-11Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- 04-11Java中你知道几种从字符串中找指定的字符的数量
- 04-11探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- 04-11Python字符串详解与示例(python字符串的常见操作)
- 04-11java正则-取出指定字符串之间的内容
- 04-11String s1 = new String("abc");这句话创建了几个字符串对象?
- 04-11java判断字符串中是否包含某个字符
- 04-11关于java开发中正确的发牌逻辑编写规范
- 最近发表
-
- Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- Java中你知道几种从字符串中找指定的字符的数量
- 探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- Python字符串详解与示例(python字符串的常见操作)
- java正则-取出指定字符串之间的内容
- String s1 = new String("abc");这句话创建了几个字符串对象?
- java判断字符串中是否包含某个字符
- 关于java开发中正确的发牌逻辑编写规范
- windows、linux如何后台运行jar(并且显示进程名)
- 腾讯大佬私人收藏,GitHub上最受欢迎的100个JAVA库,值得学习
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)