15.轮转数组

125 阅读2分钟

题目链接

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

输入: 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]

解法1 暴力

思路

按照题目意思来,就是往头部插入最后一个元素。

代码

function rotate(nums: number[], k: number): void {
    while (k--) {
        nums.unshift(nums.pop());
    }
};

时空复杂度分析

时间复杂度:删除是 O(1) 的操作,但是往队头插入需要把剩下数组元素往后挪,时间开销是 O(n) ,循环 k 次,总的时间复杂度是 O(k * n)

空间复杂度:O(1)

解法2 三次翻转

思路

把整个数组翻转一次,然后把前 k 个数反转,再把剩下的数反转,就得到了反转后的数组。 但是注意,针对于 k 大于数组长度的情况,需要对 k 进行取模。

为什么取模 k %= nums.length;

如果 k 比数组长度大,我们只需要旋转 k % nums.length 次就可以达到相同的效果,而且还不会产生空指针异常。

例子:

假设数组 nums = [1, 2, 3, 4, 5],长度为 n = 5

如果 k = 7,这意味着你希望将数组向右旋转 7 次。

实际上旋转数组 5 次会让它恢复原状,因为旋转 5 次等于没有旋转。因此,旋转 7 次的效果与旋转 7 % 5 = 2 次是相同的。

也就是说,旋转 k 次和旋转 k % n 次是等价的,因为旋转 n 次等同于不旋转。

代码

function rotate(nums: number[], k: number): void {
    const reverse = (arr: number[], start: number, end: number) => {
        while (start <= end) {
            const temp = arr[start];
            arr[start++] = arr[end];
            arr[end--] = temp;
        }
    }

    k %= nums.length;
    reverse(nums, 0, nums.length - 1);
    reverse(nums, 0, k - 1);
    reverse(nums, k, nums.length - 1);
};

时空复杂度分析

时间复杂度:O(n),总共进行了三次反转,每次反转最多遍历整个数组

空间复杂度:O(1)