公众号:爱写bug(ID:icodebugs)
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
Given an array, rotate the array to the right by k steps, where k is non-negative.
输入: [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]
输入: [-1,-100,3,99] 和 k = 2 输出: [3,99,-1,-100] 解释: 向右旋转 1 步: [99,-1,-100,3] 向右旋转 2 步: [3,99,-1,-100]
如果按照示例那种一步一步向右移,太慢。我们直接看 示例1输入 和 最终结果输出(移动步数k=3):
输入: [1,2,3,4,5,6,7]
找一下规律,我起先是以为直接以该索引 i 与 i+3 交换位置,不过仔细看一下就发现错的太离谱了。
我们可以发现输出前三位数是输入的后三位,输出后四位数是输入的前四位。而 移动步数 k=3 , 剩余长度=数组长度 - 移动步数 = 7-3=4 ,刚好对应我们发现的规律。
只要截取输入的 后k位 的数组与 输入的 剩余长度 的数组,即为所求: [5,6,7]+[1,2,3,4]
但是:题目要求使用空间复杂度为 O(1) 的 原地 算法。这在python中可以利用切片特性直接像上面那样截取,而空间复杂度不变。但是在CC++、Java里是肯定会改变空间复杂度,不满足要求。
这时候可以换个思路,如下所示不断反转特定长度数组:
输入: [1,2,3,4,5,6,7]
反转整个数组: [7,6,5,4,3,2,1]
反转前k位:[5,6,7]
反转剩余的: [1,2,3,4]
输出: [5,6,7,1,2,3,4]
或者改变一下顺序先反转前 剩余位数和后k位:
输入: [1,2,3,4,5,6,7]
反转前剩余长度的: [4,3,2,1]
反转后k位:[7,6,5]
此时数组:[4,3,2,1,7,6,5]
反转整个数组: [5,6,7,1,2,3,4]
输出: [5,6,7,1,2,3,4]
class Solution { public void rotate(int[] nums, int k) { int numsLen=nums.length,temp; k=k%numsLen; if(k==0) return; swapArray(nums,0,numsLen-1);//反转整个数组 swapArray(nums,0,k-1);//反转0到k-1索引,前k位的数组 swapArray(nums,k,numsLen-1);//反转k到末尾索引,后剩余位数位的数组 } private void swapArray(int[] nums,int start,int end){//反转函数 int temp; for (int i=start,j=end;i<j;i++,j--){ temp=nums[i]; nums[i]=nums[j]; nums[j]=temp; } } }
注:Java段代码是以反转方法里介绍的第一个方法为例,第二种方法只要改变一下
swapArray(nums,0,numsLen-1);//反转整个数组 swapArray(nums,0,k-1);//反转0到k-1索引,前k位的数组 swapArray(nums,k,numsLen-1);//反转k到末尾索引,后剩余位数位的数组
的顺序和参数即可,不再复现。
class Solution: def rotate(self, nums: List[int], k: int) -> None: """ Do not return anything, modify nums in-place instead. """ nums_len = len(nums) k = k%nums_len nums[0:nums_len] = nums[nums_len-k:] + nums[:nums_len-k]#切片组成新数组