旋转数组

243 阅读2分钟

这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

问题描述

LeetCode189. 旋转数组

一个数组A中存有 n 个整数,在不允许使用另外数组的前提下,将每个整数循环向右移 M( M >=0)个位置,即将A中的数据由(A0 A1……An-1 )变换为(An-m…… An-1 A0 A1……An-m-1)(最后 M 个数循环移至最前面的 M 个位置)。

示例:

输入:[1,2,3,4,5,6,7]

输出:[5,6,7,1,2,3,4]

分析问题

这道题最直观的想法就是使用额外的数组来将每个元素放到正确的位置。我们用n来表示数组的长度,然后遍历原数组,将原数组下标为i的元素放至新数组下标为 (i+k) % n 的位置,最后将新数组拷贝到原数组即可。

class Solution:
    def rotate(self,nums,k):
        n=len(nums)
        tmp=[0]*n

        for i in range(0,n):
            #将数组nums[i]放到新数组的相应位置
            tmp[(i+k)%n]=nums[i]
        #将新数组拷贝到原数组
        nums[:]=tmp[:]

该算法的时间复杂度是O(n),空间复杂度也是O(n)。但是题目要求不允许使用另外的数组,显然该算法是不符合题意的。我们来观察一下数组移动前后的变化,当我们将数组的元素向右移动k次后,尾部 k mod n个元素会移动至数组的头部,其余元素向后移动k mod n 个位置。因此我们可以采用数组翻转的方法来求解。具体思路如下:首先我们将所有元素进行翻转,这样尾部k mod n个元素就被移动到数组的头部。然后我们再翻转 [0, (k mod n)-1] 区间的元素和 [k mod n, n-1]区间的元素,即能得到最后的答案。

image-20211103213730385

下面我们来看一下代码的实现。

class Solution:
    #对数组中的元素进行翻转
    def reverse(self,nums,start,end):
        while start < end:
            tmp=nums[start]
            nums[start]=nums[end]
            nums[end]=tmp
            start=start+1
            end=end-1
    def rotate(self,nums,k):
        n=len(nums)
        k=k%n
        #对数组进行反转
        self.reverse(nums,0,n-1)
        #对区间nums[0,k-1]再进行翻转
        self.reverse(nums,0,k-1)
        #对区间nums[k,n-1]再进行翻转
        self.reverse(nums,k,n-1)

该算法的时间复杂度是O(n),空间复杂度是O(1)。