LeetCode 189. 轮转数组

189. 轮转数组

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 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]
向右轮转 2 步: [3,99,-1,-100]

提示:

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

进阶:

  • 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
  • 你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?

提示 1

The easiest solution would use additional memory and that is perfectly fine.


提示 2

The actual trick comes when trying to solve this problem without using any additional memory. This means you need to use the original array somehow to move the elements around. Now, we can place each element in its original location and shift all the elements around it to adjust as that would be too costly and most likely will time out on larger input arrays.


提示 3

One line of thought is based on reversing the array (or parts of it) to obtain the desired result. Think about how reversal might potentially help us out by using an example.


提示 4

The other line of thought is a tad bit complicated but essentially it builds on the idea of placing each element in its original position while keeping track of the element originally in that position. Basically, at every step, we place an element in its rightful position and keep track of the element already there or the one being overwritten in an additional variable. We can't do this in one linear pass and the idea here is based on cyclic-dependencies between elements.

解法1:使用额外的数组

Java版: 

class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        k = k % n;
        int[] copy = new int[n];
        System.arraycopy(nums, 0, copy, 0, n);
        for (int i = 0; i < n; i++) {
            nums[i] = copy[(i - k + n) % n];
        }
    }
}

Python3版:

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        copy = nums.copy()
        n = len(nums)
        k %= n
        for i in range(0, len(nums)):
            nums[i] = copy[(i - k + n) % n]
复杂度分析
  • 时间复杂度:O(n),n是 数组 nums 的长度。
  • 空间复杂度:O(n),n是 数组 nums 的长度。

解法2:

将数组中的元素向右轮转 k 个位置,可以倒着遍历数组,提前把最后 k 个数保存。这样后面的数组更改值后,不影响前面的替换。

class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        k = k % n;
        int[] copy = new int[k];
        System.arraycopy(nums, n - k, copy, 0, k);
        for (int i = n - 1; i >= k; i--) {
            nums[i] = nums[i - k];
        }
        System.arraycopy(copy, 0, nums, 0, k);
    }
}
复杂度分析
  • 时间复杂度:O(n),n是 数组 nums 的长度。
  • 空间复杂度:O(k),k是输入的值。

解法3:数组翻转

当我们将数组的元素向右移动 k 次后,尾部 k mod n 个元素会移动至数组头部,其余元素向后移动 k  mod  n 个位置。

该方法为数组的翻转:我们可以先将所有元素翻转,这样尾部的 k  mod  n 个元素就被移至数组头部,然后我们再翻转 [0,k  mod  n − 1] 区间的元素和 [k  mod  n ,n−1] 区间的元素即能得到最后的答案。

我们以 n=7,k=3 为例进行如下展示:
原始数组                                    1 2 3 4 5 6 7
翻转所有元素                             7 6 5 4 3 2 1
翻转 [0,k mod n−1] 区间的元素   5 6 7 4 3 2 1
翻转 [k mod n,n−1]区间的元素    5 6 7 1 2 3 4

 先翻转所有元素,再翻转前 k 个元素,再翻转剩余元素。

Java版:

class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        k = k % n;
        reverse(nums, 0 , n -1);
        reverse(nums, 0, k - 1);
        reverse(nums, k, n - 1);
    }

    private void reverse(int[] nums, int start, int end) {
        while (start < end) {
            int temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            start++;
            end--;
        }
    }
}

Python3版:

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        def reverse(i: int, j: int) -> None:
            while i < j:
                nums[i], nums[j] = nums[j], nums[i]
                i += 1
                j -= 1

        n = len(nums)
        k %= n
        reverse(0, n - 1)
        reverse(0, k - 1)
        reverse(k, n - 1)
复杂度分析
  • 时间复杂度:O(n),其中 n 为数组的长度。每个元素被翻转两次,一共 n 个元素,因此总时间复杂度为 O(2n) = O(n)。
  • 空间复杂度:O(1)。
  • 29
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值