题目描述
若存在一个数组,将数组中的元素向右轮转 k 个位置(其中 k 是非负数)
关于轮转的概念如下我举一个例子
如存在数组 ,我们向右轮转 1 个单位,则轮转后的数组为
C 语言具体代码实现
这道题我刚开始是没有思路的,于是借鉴了官方的方法:使用额外的数组!!!
简单来讲,对于在原数组中位于索引 0 的元素,当我们向右轮转 k 个单位,那么这个元素应该被保存在额外数组索引为 0+k 位置;但是这样并不完善,对于原数组比较靠后的元素,如 中,我们向右轮转 1 个单位,对于 4 这个元素,原索引为 3,那么其新的索引应该为
#include <stdio.h>
void rotate(int *nums, int numsSize, int k){
int newarr[numsSize]; // 使用额外的数组
for(int i = 0; i < numsSize; i++){
newarr[(i+k)%numsSize] = nums[i];
}
for(int i = 0; i < numsSize; i++){
nums[i] = newarr[i];
}
}
int main(void){
int nums[] = {1, 2, 3, 4, 5, 6};
rotate(nums, 6, 3); // 向右轮转三个单位
// 格式化输出
printf("[");
for(int i = 0; i < 6; i++){
if(i != 5){
printf("%d,", nums[i]);
}else{
printf("%d", nums[i]);
}
}
printf("]");
// [4,5,6,1,2,3]
return 0;
}
然后谈另一种方法:翻转数组!!!
该方法(数组的翻转)基于如下的事实:当我们将数组的元素向右移动 k 次后,尾部 个元素会移动至数组头部,其余元素向后移动 个位置
要实现题目中的轮转数组,我们得翻转数组多次,即先将所有元素翻转,那么尾部的 个元素就被移至数组头部,然后再翻转区间
我们以 为例进行如下展示:
操作 | 结果 |
---|---|
原始数组 | 1 2 3 4 5 |
翻转所有元素 | 5 4 3 2 1 |
翻转 [0, k%n-1] 区间的元素 | 4 5 3 2 1 |
翻转 [k%n, n-1] 区间的元素 | 4 5 1 2 3 |
#include <stdio.h>
// 交换二个元素
void swap(int *a, int *b) {
int t = *a;
*a = *b, *b = t;
}
// 翻转
void reverse(int *nums, int start, int end) {
while(start < end){
swap(&nums[start], &nums[end]);
start += 1;
end -= 1;
}
}
// 轮转
void rotate(int *nums, int numsSize, int k) {
k %= numsSize; // 取余
reverse(nums, 0, numsSize - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, numsSize - 1);
}
int main(void){
int nums[] = {1, 2, 3, 4, 5, 6};
rotate(nums, 6, 3); // 向右轮转三个单位
// 格式化输出
printf("[");
for(int i = 0; i < 6; i++){
if(i != 5){
printf("%d,", nums[i]);
}else{
printf("%d", nums[i]);
}
}
printf("]");
// [4,5,6,1,2,3]
return 0;
}