1. 这道题为什么会成为面试高频题
轮转数组(Rotate Array)在LeetCode上是第189题,难度标的是中等,但说实话,这道题的上限和下限差距非常大。我见过不少候选人在这道题上栽跟头,也见过有人靠这道题直接拿到offer——区别不在于会不会做,而在于能给出几层解法的递进。
题目本身很简单:给你一个数组,将数组中的元素向右轮转 k 个位置。比如 [1,2,3,4,5,6,7],k=3,结果是 [5,6,7,1,2,3,4]。
之所以高频,是因为它考察的不是某个冷门算法,恰恰是数组操作中最基础也最容易出错的两个能力:索引下标的数学推导能力,以及空间复杂度优化的思维层次。很多人一上来就能给出第一种解法,但能一口气写出三种解法并讲清楚每种解法的取舍,就完全是两个水平了。
另外还有个实际原因:这道题的变体在真实业务里太常用了。消息队列的消费位点回退、图片轮播图的循环切换、日程表按周循环排列,甚至游戏里音效数组的循环播放,本质都是轮转。刷题不能只为了面试,很多题你刷完就忘了,但这道题的思路是会真正写进业务代码里的。
这篇文章我按照自己刷这道题时的思考路径来写:先讲最直观的暴力解,再优化到空间换时间,最后给出最优的三次翻转法。每一层我都会讲清楚为什么这样做、复杂度怎么算、以及面试官可能会追问什么。最后再补充一些扩展变形和实际面试中的小建议。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 先从暴力解法入手:能跑通,但别止步于此
2.1 最容易想到的写法
拿到这道题,大部分人第一反应是:每次向右轮转一个位置,执行 k 次。右移一个位置的操作就是保存最后一个元素,然后把前面所有元素往后挪一位,最后把保存的元素放到开头。
python复制def rotate(nums, k):
n = len(nums)
k = k % n # 注意这里,后面会解释
for _ in range(k):
last = nums[n - 1]
for i in range(n - 1, 0, -1):
nums[i] = nums[i - 1]
nums[0] = last
这段代码在LeetCode上能通过,但效率很惨。外层循环执行 k 次,内层循环每次要移动 n-1 个元素,时间复杂度是 O(k×n)。当数组长度是一万、k 是五千的时候,就是五千万次赋值操作,跑起来明显卡顿。
2.2 为什么必须对 k 取模
这里有个新手很容易忽略的细节:k 可能大于数组长度。比如数组长度是 7,k=10,轮转 10 次和轮转 3 次的效果完全一样,因为每轮转 7 次数组就回到原样了。
所以第一步一定先取模:
python复制k = k % n
取模之后 k 一定小于 n,这样能避免大量无效循环。一个长度为 7 的数组,k=1000000,不取模的话暴力解法要执行一百万次循环,取模后只需要执行 3 次。
注意:取模这一步不是可选项,是必须的。LeetCode的测试用例里一定有 k > n 的数据。哪怕你用的是后面更优的解法,第一步也要先取模。
2.3 暴力解法的真实定位
暴力解法虽然效率低,但它的价值在于:它是验证其他解法正确性的基准。我自己在写最优解的时候,会先用暴力解跑一遍小样本数据,把结果当作
