题目:旋转数组
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: [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:
输入: [-1,-100,3,99] 和 k = 2
输出: [3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]
说明:
- 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
- 要求使用空间复杂度为 O(1) 的 原地 算法。
代码
C语言:(我这里用的是 方法 3:使用环状替换 )
void rotate(int* nums, int numsSize, int k){
k = k%numsSize; // 移动k个位置; numsSize是数组中元素的个数
int count = 0; //什么时候就可以保证每个元素都换完了呢?n个元素,换n次,所以用一个count来计数。
int start = 0;
int current,prev;
int next,temp;
while (count < numsSize){ //控制跳跃次数
current = start; // 让current充当一个指针,指向开头的位置 ,
prev = nums[start]; //利用 Prev 获取当前指针的数据
//这里相当于用 current 存当前元素下标,用 prev 存放值
// 这里是先执行再判断
do {
next = (current +k) % numsSize; // 这里求的是元素 prev 要移到哪个位置,用 next表示
temp = nums[next]; // 用temp 先把要占的位置上的值存起来
nums[next] = prev; // prev 移到了next的位置
prev = temp; //把被占的元素 暂时赋值给prev
current = next; //又从next位置开始,计算下一个要替换的位置.注意此时next所指的值已不是原来的了,但是没影响
count++;
}while (start != current);//如果跳回远点,但还未达到跳远次数,就结束循环从下一个数开始
start++;
}
}
第一遍看不懂答案的,建议先跟着答案敲一遍代码,可以边写代码边简单的写一写注释。
思路 / 算法思想
参考链接:https://leetcode-cn.com/problems/rotate-array/solution/189-xuan-zhuan-shu-zu-cyu-yan-by-realjimmy/,非常感谢这位大佬的分享,终于懂了。
针对上面给出的代码,写一下思路梳理:
1)首先一个while 循环 ————————控制跳的次数,每跳一次就代表换完了一个数,所有的数都换完了就结束。
2)while 循环 里面加了一个do while循环————————用来计算出计算出每个元素最终所在的位置,比如k=3, nums[0]替换掉nums[3],再从下标3 开始,计算下一个要替换的位置。这步需要注意的是,不是把nums[0]和nums[3]直接交换,而是nums[3]先存起来用于下次替换,然后再 nums[0]替换nums[3]。
如果只有五个元素,一开始 start=0,则有 num[0]先跳到num[3], 原本的num[3] 则跳到 num[0] 。 但这又回到了原点,如果再继续跳,又从下标0开始,计算下一个要替换的值,这样就一直重复计算了。 所以应该结束 do while 循环,然后 start++————从下一个位置开始 进入do while循环。 也就是从下标1开始进入 do while 循环。
3)一直到 所有的数都换完,结束 while 循环