刷题网站:Leetcode
难度: 中等
语言: Python
计划:从简单——>到中等——>再到难。
一、189旋转数组
1.1 题目:
给定一个数组,将数组中的元素向右移动 k
个位置,其中 k
是非负数。
-
进阶:
尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗? -
示例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.2 思考分析
初看本题,题目很短,但是难度是中等难度,所以还需重视。先理解题目大概意思,即给定一个数组和k
值,然后把最后k
个值放到前面来,形成一个新的数组输出。
首先,我想的是以k
为切分,将数组分成了两部分,然后替换前后两部分的顺序即可。也就是将数组中第n-k
个索引位置,挪到第0
个索引位置,然后再将第n-k+1
个索引位置,挪到第1
个索引位置,以此类推,直至到最后一个。但同时也要将前面的第0
个索引位置,挪到第k
个索引位置,第1
个索引位置,挪到第k+1
个索引位置,以此类推,直至第n-k
个位置。
但是,我们会发现一个问题,就是索引位置值的替换会有重复的,即当替换一个索引位置后,到后面可能重复替换了,所以我想先假设一个空数组,然后填充进去,而不是直接在原数组上替换。
故,完整代码如下(以下是我在Sublime text3上面运行的代码):
from typing import List
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
n = len(nums)
nums2 = [1]*n
i,j = 0,0
m = k
while m < n:
nums2[m] = nums[j]
if k>0:
nums2[i] = nums[n-k]
k-=1
i+=1
m+=1
j+=1
return nums2
print(Solution().rotate([1,2,3,4,5,6,7],3))
print(Solution().rotate([-1,-100,3,99],2))
输出:
[5, 6, 7, 1, 2, 3, 4]
[3, 99, -1, -100]
[Finished in 0.1s]
初看结果,好像正确。但是,当我将代码输入到Leetcode执行的时候,竟然提示我错误,这就很纳闷,不知道错在哪里。在上面显示输出还是原数组,但是我笔算和计算机算都是正确的结果,为什么会错呢?
然后,根据代码中的提示
"""
Do not return anything, modify nums in-place instead.
"""
提示不需要返回值,然后我把return
删了,执行还是错误。
然后翻开评论,许多人也有我一样的问题,有的说是必须在原数组上修改,return没用,不知道怎么回事?
接着我们看题解的方法三,用到的思想是数组翻转。
大概意思是:==先将所有元素翻转,尾部k mod n
个元素就被移至数组头部(此处取模是因为题目给出的k可能大于n,其翻转k
次要取模),然后再翻转[0, k mod n-1]
区间的元素和[k mod n, n-1]
区间的元素,即可。
由于python中的reverse()
函数没有指定某前面几个数翻转(也可能是我不知道),故需要自己先定义一个翻转函数。
def reverse(self, nums):
n = len(nums)-1
i = 0
while i<n:
j = nums[i]
nums[i] = nums[n]
nums[n] = j
i+=1
n-=1
return nums
然后再rotate()
函数里调用它实施翻转,故完整代码如下:
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
k %=len(nums)
self.nums = self.reverse(nums)
self.nums[0:k] = self.reverse(nums[0:k])
self.nums[k:] = self.reverse(nums[k:])
print(nums)
def reverse(self,nums):
n = len(nums) -1
i = 0
while i < n:
j = nums[i]
nums[i] = nums[n]
nums[n] = j
i+=1
n-=1
return nums
执行结果通过,如下
虽然通过,但是算法应该不是最佳的。
1.3 总结
想想此题其实本身不难,也能解答,但是要按照要求作答就比较难想。就比如我们之前的方法是可以进行翻转的,但是提交就会有问题,是因为我们没考虑运行内存问题,故最终只能按照题解中的算法思想来求解。