轮转数组

标签: 数组 数学 双指针

难度: Medium

给定一个整数数组 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 <= 105
  • -231 <= nums[i] <= 231 - 1
  • 0 <= k <= 105

进阶:

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

Submission

运行时间: 28 ms

内存: 23.4 MB

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        k = k % len(nums)
        nums[:] = nums[-k:] + nums[:-k]

Explain

这个题解的思路是直接切片。首先将 k 对数组长度取模,得到实际需要轮转的次数。然后将原数组切片为两部分:后 k 个元素 nums[-k:] 和除去后 k 个元素的部分 nums[:-k],再将这两部分拼接起来赋值给原数组,即可得到轮转后的结果。

时间复杂度: O(n)

空间复杂度: O(1)

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        # 对 k 取模,得到实际需要轮转的次数
        k = k % len(nums)
        # 将原数组切片为两部分并拼接,赋值给原数组
        nums[:] = nums[-k:] + nums[:-k]

Explore

这个操作是为了处理当旋转次数`k`大于数组长度的情况。取模操作确保了实际的旋转次数不会超过数组的长度,因此可以避免无效的多次全数组旋转,提高效率。如果不进行这一步操作,当`k`大于数组长度时,数组会进行多余的完整旋转,这不仅增加了计算量,而且是不必要的,因为每旋转一次数组长度,数组状态会恢复到原始状态。

使用切片来实现数组的轮转简单直观,但在面对极大的数组时可能会有性能问题,因为切片操作涉及到额外的数组复制。在Python中,这种方法的时间复杂度是O(n),空间复杂度也是O(n)。存在更高效的方法,例如使用环状替换或三次数组翻转(先整体翻转,再翻转前k个元素,最后翻转剩余元素)实现原地旋转,可以将空间复杂度降低到O(1)。

是的,题解中的方法能正确处理这些特殊情况。当`k`等于0时,`k % len(nums)`的结果也是0,此时不会进行任何旋转,数组保持原样。当`k`等于数组长度时,`k % len(nums)`的结果同样是0,同样不进行任何旋转,数组也保持原样。因此,这种方法能够适应这些边界情况。