题目描述:
给你一个数组,将数组中的元素向右轮转 k
个位置,其中 k
是非负数。
(来源:leetcode)
1.数组拆分
//经观察发现:将数组元素全部后移k单位即将后 k%length 个元素前置,为此我们可以借助一个新数组存储这些 需要前置的元素,然后整体迁移。
void rotate(int* nums, int numsSize, int k){
k = k % numsSize;
if(!nums || numsSize < 2 || k <= 0) return;
int maxInd = numsSize - 1;
int oriInd = maxInd - k;
int opInd = oriInd + 1;
int i, j = 0;
int temp[k];
for(i = 0;i < k; i++){
temp[i] = nums[opInd++];
} //存储需要前置的元素
for(i = oriInd; i >= 0; i--){
nums[maxInd--] = nums[i];
} //剩余元素后置
for(i = 0; i < k; i++){
nums[i] = temp[i];
} //元素前置
}
2.暴力解法
//新创建一个数组,按原数组旋转后的正确顺序到新数组中,再放回。
void rotate(int* nums, int numsSize, int k){
if(!nums || numsSize == 0 || k == 0) return;
int i, temp[numsSize];
for(i = 0; i < numsSize; i++){
temp[(i+k)%numsSize] = nums[i];
} //在新数组的元素移动后位置摆放各个元素
for(i = 0; i < numsSize; i++){
nums[i] = temp[i];
} //拷贝回原数组
}
3.三次原地反转
//思路同一,需要把后 K 个元素前置,可以先将整个数组翻转,再把前 k 个元素翻转,最后剩余元素翻转。这种方法空间复杂度低。
void rotate(int* nums, int numsSize, int k){
if(!nums || numsSize < 2 || k == 0) return;
k = k % numsSize;
int i;
for(i = 0; i < numsSize / 2; i++){
nums[i] = nums[i] + nums[numsSize-i-1];
nums[numsSize-i-1] = nums[i] - nums[numsSize-i-1];
nums[i] = nums[i] - nums[numsSize-i-1];
} // 整个数组翻转
for(i = 0; i < k / 2; i++){
nums[i] = nums[i] + nums[k-i-1];
nums[k-i-1] = nums[i] - nums[k-i-1];
nums[i] = nums[i] - nums[k-i-1];
} // 前 k 个元素翻转
for(i = k; i < (numsSize + k) / 2; i++){
nums[i] = nums[i] + nums[numsSize-1-i+k];
nums[numsSize-1-i+k] = nums[i] - nums[numsSize-1-i+k];
nums[i] = nums[i] - nums[numsSize-1-i+k];
} // 剩余元素翻转
}
4.临时变量
// 借助一个临时变量持续元素向后迁移。但需要注意当 length%k = 0 时,这一特殊条件。
void rotate(int* nums, int numsSize, int k){
if(!nums || numsSize < 2 || k == 0) return;
k = k % numsSize;
int temp = nums[0], i = 0, j = k, t, count = 0;
while(i++ < numsSize){ //持续对每一个元素都摆放到正确位置
t = nums[j];
nums[j] = temp;
temp = t;
if(j == count){ //当 j 又回到出发点时说明发生了原地打转
count = (count + 1) % numsSize; //从下一个开始
j = count;
temp = nums[j];
}
j = (j + k) % numsSize; //j用来寻找当前元素的移动后落脚点
}
}