LeetCode 189题
问题描述:
Given an array, rotate the array to the right by k steps, where k is non-negative.
Example 1:
Input:[1,2,3,4,5,6,7]
and k = 3 Output:[5,6,7,1,2,3,4]
Explanation: rotate 1 steps to the right:[7,1,2,3,4,5,6]
rotate 2 steps to the right:[6,7,1,2,3,4,5]
rotate 3 steps to the right:[5,6,7,1,2,3,4]
Example 2:
Input: [-1,-100,3,99]
and k = 2
Output: [3,99,-1,-100]
Explanation:
rotate 1 steps to the right: [99,-1,-100,3]
rotate 2 steps to the right: [3,99,-1,-100]
Note:
- Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.
- Could you do it in-place with O(1) extra space?
class Solution:
def rotate(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: void Do not return anything, modify nums in-place instead.
"""
lens = len(nums)
k = k % lens
for i in range(0, k):
tmp = nums[lens - 1]
for j in range(lens - 1, - 1, -1):
nums[j] = nums[j - 1]
nums[0] = tmp
这是第一次给出的解法。根据题目意思很容易知道当k==len(nums)时,数组不变,即只需要移动k = k % len(nums)即可,后面就是循环移动数组了。然而,由于循环次数太多,当数组过大时很容易超时,在这个解法中需要移动 k * (n - 1)次,需要尽可能地减少移动次数。
如果用一个额外的数组,那么只需要遍历一次就可以了。但是这样就没什么难度了。
经过观察发现向右循环移动k次,实际上等价于向左循环移动(n - k)次,可以尝试从两者选择移动次数最少的一种。但是在最坏的情况下,也就是k = n / 2时,仍需要(n / 2)* (n - 1)次移动,还是不够。
实际上,移动前数据的下标与移动后数据的下标之间的关系是确定的,可计算的,其关系为可表示为idxAfter = (idxBefore + k) % len(nums)。
class Solution:
def rotate(self, nums, k):
lens = len(nums)
k = k % lens
count = 0
for i in range(0, k):
if count == lens:
break
tmp = nums[(i + k) % lens]
nums[(i + k) % lens] = nums[i]
j = (i + k) % lens
count += 1
while j != i:
tmp2 = nums[(j + k) % lens]
nums[(j + k) % lens], tmp = tmp, tmp2
j = (j + k) % lens
count += 1
从下标0开始,移动数组内元素。移动时会覆盖掉下一个位置的元素,因此用一个临时变量先将其存起来。另外由于取余的效果,下标的变化是循环的,因此以循环一轮作为while的退出条件(没有do while语句,因此在进入while之前,先移动一次)。而for语句是循环的次数,有两种情况,一种是只循环一次,遍历数组,第二种是循环k次,每次遍历n/k个元素,但不论何种循环方式,其访问的元素个数均为len(nums)个。以count记录已遍历的元素个数,当count == lens时,即移动结束,退出for循环。