算法学习(题解)
1.题目
给定一个整数数组nums
,将数组中的元素向右轮转k
个位置,其中 k
是非负数。
2.实例
输入: 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]
3.思路
-
临时数组: 最直接的方法使用一个临时数组,复制原数组的值, 将每个元素后移
k%nums.length
位即可 -
环形旋转: 从第一个开始, 依次往后移动
k%nums.length
位, 取出目标位置的值, 赋上原位置的值, 如图所示:
但是如果
nums.length%k=0
, 也就是数组长度为k的倍数时会陷入死循环, 就有以下两种解决方法:- 使用一个数组记录已经处理过的位置, 使用布尔类型的数组可能稍微方便一点
public void rotate(int[] nums, int k) { int temp = 0,a = 0, exchange = 0, count = 0, len = nums.length; boolean[] arr = new boolean[len]; k %= len; if(nums == null||len ==1||k == 0){ return ; } exchange = nums[0]; for(int i = 0;i < len;i++){ if(arr[a]){ a = (a + 1)%len; exchange = nums[a]; i--; }else{ a = (a+k)%len; temp = nums[a]; nums[a] = exchange; exchange = temp; arr[a] = true; } } }
- (真正的原地算法) 因为第一次出现特殊情况时
nums.length%k=0
, 也就是说起始循环位置——索引为0
,而count
通过依次自增 , 充当了记录起始循环位置索引的职责, 实现十分巧妙
public void rotate(int[] nums, int k) { int temp = 0,a = 0, exchange = 0, count = 0, len = nums.length; k %= len; if(nums == null||len ==1||k == 0){ return ; } exchange = nums[0]; for(int i = 0;i < len;i++){ a = (a+k)%len; temp = nums[a]; nums[a] = exchange; exchange = temp; if(a%len == count){ count++; a = count; exchange = nums[a%len]; } } }