在问 · 算法题解

189. 轮转数组

题目描述

输入整数数组 nums 和非负整数 k。把数组整体向右循环移动 k 个位置:每移动一步,最后一个元素就挪到最前面。

直接在 nums 上修改,不需要返回值。页面展示的输出是修改后的 nums。k 可能大于数组长度。

示例 1
输入:nums = [1,2,3,4,5,6,7], k = 3
输出:[5,6,7,1,2,3,4]

解释:右移 1 步得 [7,1,2,3,4,5,6],2 步得 [6,7,1,2,3,4,5],3 步得 [5,6,7,1,2,3,4]。

示例 2
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]

解释:右移 1 步得 [99,-1,-100,3],再移 1 步得 [3,99,-1,-100]。

数据范围

  • 1 <= nums.length <= 10^5
  • -2^31 <= nums[i] <= 2^31 - 1
  • 0 <= k <= 10^5

进阶:尽量想出多种做法,本题至少有三种不同思路。能否只用 O(1) 额外空间原地完成?

解题思路:三次翻转

k 先对 n 取模。整体翻转,再分别翻转前 k 个和后 n-k 个元素,即可把尾部移到前面且保持各段内部顺序。

为什么正确

每次翻转后,目标数组被拆成的两段位置关系已经正确,只需恢复段内顺序。

复杂度分析

时间 O(n),空间 O(1)。

易错点

k 可能大于数组长度,必须先 k%=n;空数组需按题目约束处理。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def rotate(self, nums,k):
        n=len(nums); k%=n
        def rev(i,j):
            while i<j: nums[i],nums[j]=nums[j],nums[i]; i+=1; j-=1
        rev(0,n-1); rev(0,k-1); rev(k,n-1)

载入编辑器,自己跑一遍 →

其他解法

额外数组靠 O(n) 空间换取简单;环状替换沿置换环逐个搬动,三次翻转用翻转的组合得到轮转,两者都是原地 O(1) 空间。

解法 2:额外数组 时间 O(n),空间 O(n)

新建一个长度为 n 的数组,把原数组下标 i 的元素放到新数组下标 (i+k) mod n 的位置。最后把新数组拷回原数组。

直接对应轮转的定义,不容易写错。需要 O(n) 额外空间,不满足进阶的原地要求。

from typing import List

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        n = len(nums)
        res = [0] * n
        for i in range(n):
            res[(i + k) % n] = nums[i]
        nums[:] = res

解法 3:环状替换 时间 O(n),空间 O(1)

从下标 start 出发,把当前元素放到 (cur+k) mod n,把被挤出的元素继续往后放,直到回到 start,完成一个环。可以证明共有 gcd(n, k) 个环,分别从 0 到 gcd(n, k)-1 出发各走一遍,每个元素恰好移动一次。

同样是 O(1) 空间,每个元素只写一次。需要理解环的个数为什么是 gcd(n, k),比三次翻转难想到。

from math import gcd
from typing import List

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        n = len(nums)
        k %= n
        for start in range(gcd(n, k)):
            cur, prev = start, nums[start]
            while True:
                nxt = (cur + k) % n
                nums[nxt], prev = prev, nums[nxt]
                cur = nxt
                if cur == start:
                    break

数组与矩阵 专题的其他题目

查看 数组与矩阵 全部题目 →