题目

从标准输入读入一个长度为 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