题目描述
思路解析动画文字版
最直觉的做法:每次把尾节点摘下来接到头前,重复 k 次。可 k 能大到上亿,挪 k 次会超时。而且旋转 n 次就回到原样——挪 k 次其实等于挪 k 除以 n 的余数次。我们要更聪明的一刀法。
① 走到尾节点、顺便数出长度 n,把尾接回头形成环;② 真正生效的旋转量是 k 余 n,新的尾节点在第 n−k 个位置;③ 从头走 n−k−1 步停在新尾,它的下一个就是新头,最后把环在这里剪断。下面用 1→2→3→4→5、k=2 慢放。
起点 · 数长度,tail 找尾:tail 从头节点 1 出发,计数 n 从 1 起步。一边走到链尾、一边把节点数出来。
tail 走到尾 · 数出 n=5:tail 一路走到 5,它的 next 是 null,停。此时 n=5——链表一共 5 个节点。
算有效旋转量 · k %= n:先给 k 取模:k = 2 % 5 = 2。如果 k 比 n 大,转一整圈白转,余数才是真正要挪的量。这里余数还是 2。
① 接环 · tail.next = head:执行 tail.next = head:把尾节点 5 接回头节点 1(图上 5 多出一根箭头绕回 1),整条链闭合成环。现在没有头也没有尾,转圈不会掉出去。
② 算新尾位置 · 走 n−k−1 步:新的尾节点在第 n−k = 3 个位置(节点 3)。从头节点 1 出发,再走 n−k−1 = 2 步就能停在它身上。cur 现在站在起点 1。
走第 1 步 · cur 到 2:cur 走一步到节点 2。还差 1 步到新尾。
走第 2 步 · cur 到新尾 3:cur 再走一步到节点 3,走满 2 步。这就是新的尾节点——它后面那个 4 将成为新头。
③ 断开 · new_tail.next = None:记下新头 new_head = 3 的 next = 4,再执行 3.next = None 把环剪断。沿着新头 4 读出来:4 → 5 → 1 → 2 → 3 → null,正是答案。
旋转的本质就是换一个起点。接环后整条链是一个圈,从哪剪开、哪就是新头——新头在第 n−k+1 个位置(节点 4),新尾在它前一个(节点 3)。
雷区实演 · k=7、n=5 不取模会怎样:若 k=7:转 5 次回原点,多出的 7−5=2 次才有效。7 % 5 = 2,结果和 k=2 完全一样。不取模就会让 new_tail 越过尾、走进环里出不来。这就是为什么第一步必须 k %= n。
面试追问:旋转链表的追问重点:取模的必要性、成环的取舍、边界的提前拦截。
「数长度 + 找第 m 个节点 + 在某处断开重接」是一整类链表题的原子操作:LC19 删倒数第 N 个(先定位)、LC24 两两交换、LC25 K 个一组翻转都靠它。学会这一道,链表的切割重组就通了——更多在 链表专题 继续,不懂可随时问右下角的 AI 助教小欧。
边界三连:旋转链表的边界都集中在 k 与 n 的关系:等于、整除、超大,取模一行全收编。
参考代码
class Solution: def rotateRight(self, head, k): if not head or not head.next or k == 0: return head n, tail = 1, head while tail.next: # 走到尾,数出长度 n tail = tail.next n += 1 k %= n # 有效旋转量 if k == 0: return head # 整圈,原样返回 tail.next = head # ① 接成环 new_tail = head for _ in range(n - k - 1): # ② 走到新尾 new_tail = new_tail.next new_head = new_tail.next new_tail.next = None # ③ 断开 return new_head复杂度
- 时间复杂度:O(n),数长度走一趟 n,定位新尾再走 n−k 步,合计不超过 2n → O(n)
- 空间复杂度:O(1),只用 tail / new_tail 等几个指针,不随链表变长 → O(1)
可套用的代码模板
骨架挖空的是「走几步到断点」那个 ?——旋转题填 n−k−1,删倒数第 N 个填 n−N−1。先数长度、可选接环、再定位断点,三类链表切割题共用这副骨架。右上角可切 C++ / Java。
# 凡是「整体平移 / 在第 m 个节点处切割」的链表题都套n, tail = 1, headwhile tail.next: # 一趟走到尾,顺便数长度 tail = tail.next; n += 1k %= n # 有效偏移,去掉整圈# tail.next = head # 需要环就接上(旋转题用)node = headfor _ in range(?): # 走到目标断点(步数按题推) node = node.next# ... 在 node 处切割 / 断开 / 重接 ...易错点
面试追问把动画讲成自己的话
追问为什么 k 要对 n 取模?
追问不接环,能直接做吗?
追问空链表或单节点会出错吗?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。再去主线里挑下一道练手。
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题