题目
从标准输入读入一个长度为 n 的数组和一个非负整数 k,将数组元素循环向左移动 k 个位置后输出。
输入格式:第一行输入整数 n 和移位数 k;第二行输入 n 个整数。
输出格式:在一行中输出循环左移后的数组,元素以空格分隔,末尾换行。
数据范围与约定:1 ≤ n ≤ 1000,0 ≤ k ≤ 106。
思路与算法
1. 模运算化简
当移动位数 k ≥ n 时,移动满 n 位相当于回到原位。因此首先执行 k %= n 减少多余轮次。
2. 两种实现方案
方案 A(辅助数组):新下标为 (i - k + n) % n 或从原数组 (i + k) % n 拷贝;
方案 B(三步反转法):先反转前 k 个元素,再反转剩余 n-k 个元素,最后反转整个数组,实现 O(1) 额外空间的原地循环移位。
完整程序
#include <stdio.h>
int main(void)
{
int n, k, a[500], tmp[500];
if (scanf("%d %d", &n, &k) != 2 || n < 1) {
return 1;
}
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
// 循环移位有效步长:移动 n 次等于回到原位
k %= n;
// 先暂存前 k 个元素
for (int i = 0; i < k; i++) {
tmp[i] = a[i];
}
// 将后 n-k 个元素整体前移 k 个位置
for (int i = 0; i < n - k; i++) {
a[i] = a[i + k];
}
// 将暂存的前 k 个元素拼接到数组末尾
for (int i = 0; i < k; i++) {
a[n - k + i] = tmp[i];
}
for (int i = 0; i < n; i++) {
printf("%d%c", a[i], i + 1 < n ? ' ' : '\n');
}
return 0;
}运行示例
输入:
5 2
1 2 3 4 5输出:
3 4 5 1 2其它写法
下面每种写法都是完整程序,输入输出格式与正文一致,便于对照。
三次反转
程序:
#include <stdio.h>
static void reverse(int *a, int l, int r)
{
while (l < r) {
int t = a[l];
a[l] = a[r];
a[r] = t;
l++;
r--;
}
}
int main(void)
{
int n, k, a[500];
if (scanf("%d %d", &n, &k) != 2 || n < 1) {
return 1;
}
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
k %= n;
reverse(a, 0, n - 1);
reverse(a, 0, k - 1);
reverse(a, k, n - 1);
for (int i = 0; i < n; i++) {
printf("%d%c", a[i], i + 1 < n ? ' ' : '\n');
}
return 0;
}输入:
5 2
1 2 3 4 5输出:
3 4 5 1 2