【Hard——Day4】25.K 个一组翻转链表

题目链接

https://leetcode.cn/problems/reverse-nodes-in-k-group/description/

题解链接

https://leetcode.cn/problems/reverse-nodes-in-k-group/solutions/2500730/dui-zhan-chu-li-by-admiring-meninskyuli-gwt9

https://leetcode.cn/problems/reverse-nodes-in-k-group/solutions/511795/python3-20s-shi-pin-dai-ni-qing-song-gao-pnj4

https://leetcode.cn/problems/reverse-nodes-in-k-group/solutions/1992228/you-xie-cuo-liao-yi-ge-shi-pin-jiang-tou-plfs

题解

我的想法是暴力法,统计出一整个数组,然后每次统计出k个数值调用API反转,并根据反转后的数组整体重新创建一个新的链表(跟之前面字节面试的时候一样)。

题解一:栈

他这个其实也是双指针法,各种提取和连接比较巧妙,还有他中途返回,不熟悉可能做不出来。

题解二:深度优先搜索、递归

和上一个解法都是使用了while True。就是反转链表的时候用到了dfs算法,其余也是需要结点个数的处理,循环重新赋值等等细节。但是这个题解写的不好,罗里吧嗦一大堆,变量命名也不规范,看了根本分不清。

题解三:链表

时间复杂度我分析错了,是O(n)不是O(n* k)。

画了个图,理解一点了最后几句,有点绕,p0每次保存的是当前处理这组k个结点的最后一个结点,也就是本组的第一个结点。

代码

python 复制代码
#25.K 个一组翻转链表
#题解一:栈
class Solution:
    def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        h = t = ListNode(0, head)
        p, stack = head, []        
        while True:
            for _ in range(k):
                if p: 
                    stack.append(p)     # 压栈
                    p = p.next
                else: return h.next     # 不满栈,直接返回
            for _ in range(k):
                t.next = stack.pop()    # 出栈,同时续到链表尾部
                t = t.next
            t.next = p                  # 连接后段链表

#题解二:深度优先搜索、递归
class Solution:
    def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
        def getK(k, start):
          	# get 第 n*k + 1 个节点
            curr = start
            for i in range(k):
                if not curr:
                    # 不够 k 个,要区分于 None
                    # 否则,无法区分 "最后一个节点恰好是第 n*k 个" 的情况
                    # (因为那时的第 n*k + 1 个节点为 None,且仍然需要经历 dfs 处理,不能提前 return)
                    return -1
                curr = curr.next
            return curr

        def dfs(pre, head, end):
            if head == end: 
                return pre, head
            nxt = head.next
            head.next = pre

            return dfs(head, nxt, end)
          
        # 准备一个虚拟头节点,用于最后返回结果        
        dummy = ListNode(-1)  
        # 根据循环的规律,提前设置好「节点 b 和 节点 d」
        b = dummy
        d = head

        while True:
          	# 准备 「节点 a 和 节点 b」
            a, b = b, d
            
            # 找到「节点 d」,是 dfs 反转链表时的结束条件
            # 第 n*k + 1 个节点,dfs 反转链表时遇到了它,就应该结束反转
            d = getK(k, b)
            
            # 如果余下的节点不够 k 个,直接返回虚拟头节点的 next
            if d == -1:
                return dummy.next

            # 反转子链表(长度为 k)
            c, d = dfs(None, b, d)
            
            # 穿针引线
            a.next, b.next = c, d
            
            # 如果总节点个数是 k 的倍数,那么就会遇到节点 d 为空的时候,直接返回虚拟头节点的 next
            if not d: 
                return dummy.next

#题解三:链表
class Solution:
    def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        # 统计节点个数
        n = 0
        cur = head
        while cur:
            n += 1
            cur = cur.next

        p0 = dummy = ListNode(next=head)
        pre = None
        cur = head

        # k 个一组处理
        while n >= k:
            n -= k
            for _ in range(k):  # 同 92 题
                nxt = cur.next
                cur.next = pre  # 每次循环只修改一个 next,方便大家理解
                pre = cur
                cur = nxt

            # 见视频
            nxt = p0.next
            nxt.next = cur
            p0.next = pre
            p0 = nxt
        return dummy.next
相关推荐
坚持编程的菜鸟8 小时前
模拟实现memmove
c语言·算法·模拟实现memmove
wabs6669 小时前
关于图论【最短路径之Dijkstra算法(堆优化版)|卡码网47.参加科学大会的思考】
数据结构·算法·图论·优先级队列·邻接表·小顶堆·卡码网
坚持编程的菜鸟10 小时前
编写判断大小端程序
c语言·算法·判断大小端
papaofdoudou10 小时前
判断排列逆序奇偶性的乘积判别法(范德蒙德符号法)
人工智能·算法
linux-hzh10 小时前
百日算法修炼 · Day 03
java·算法
问商十三载11 小时前
RAG 检索效果差怎么排查?2026 五层诊断法完整指南
开发语言·人工智能·windows·python·算法
嵌入式老牛11 小时前
三相电气量采集模块设计(三)非同步采样时的精度提升
算法·精度·计量
今天AI了吗12 小时前
精细化落地教程:TimechoAI调参标准+数据清洗规范+误差归因+阈值适配全维度指南
大数据·人工智能·算法
zephyr0513 小时前
从递归到迭代:二叉树非递归前中后序遍历详解
算法
evans在进步13 小时前
LeetCode 2 两数相加:链表模拟加法,Java 图解进位过程
java·leetcode·链表