• PAT B1008——数组元素循环右移


    方法1

    不进行重排,直接从指定位置循环输出。

    方法2

    按照题目要求用最少交换次数重排。

    具体算法:

    1. 选择第i号数字作为起始位(索引从0开始)。将起始位的数字拿出储存,然后剩下数字依次填补上一个空缺,直到返回起始位。
    2. 由N-M至N-M+d-1依次作为起始位,进行步骤1。结束后即完成重排。(注:d为MN的最大公约数)
    • 例如:假设N=6,M=4
      第一次取出索引为2的数字3,然后依次填补空缺。
      1 2 X 4 5 6
      1 2 5 4 X 6
      X 2 5 4 1 6 //下次移动的数字将为2号位,所以停止
      3 2 5 4 1 6 //放回3
      第二次第一次取出索引为3的数字4,然后依次填补空缺。
      3 2 5 X 1 6
      3 2 5 6 1 X
      3 X 5 6 1 2 //下次移动的数字将为3号位,所以停止
      3 4 5 6 1 2 //放回4
      完成

    分析

    其实不必非要从N-M开始至N-M+d-1结束,依次选取连续的d个数作为起始位即可。

    • 因为每次步骤1的跨度为K(设K为最大公倍数),K/M即为每次步骤1所重排的数字个数。(因为移动的距离为4,而返回起始位需要移动距离为6的倍数,所以完成一次步骤1一共跨越了12个数,有3个数字被重排

    • 每个数字经历一次重排就可到达指定位置,且一共有N个数字需要重排,N/(K/M)即为需要进行步骤1的次数。(MN/K即d,因此进行d次步骤1即可)

    • 易知连续地选取起始位即可使每个数字都被重排。

    参考代码

    #include <cstdio>
    int gcd(int a, int b) {
        if(b == 0) return a;
        else return gcd(b, a % b);
    }
    int main() {
        int a[110];
        int n, m, temp, pos, next;
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
        }
        m = m % n;
        if(m != 0) {
            int d = gcd(m, n);
            for(int i = n - m; i < n - m + d; i++) {
                temp = a[i];
                pos = i;
                do {
                    next = (pos - m + n) % n;
                    if(next != i) a[pos] = a[next];
                    else a[pos] = temp;
                    pos = next;
                }while(pos != i);
            }
        }
        for(int i = 0; i < n; i++) {
            printf("%d", a[i]);
            if(i < n - 1) printf(" ");
        }
        return 0;
    }
    
  • 相关阅读:
    spark java wordCount实例
    SpringMVC 商城项目
    jstl 遍历数据
    jquery 方法总结
    8ch
    7ch
    使用vuex实现组件间传值
    Vue父子组件之间传值
    从浏览器输入URL地址到最终页面渲染完成,发生了什么?
    数组去重
  • 原文地址:https://www.cnblogs.com/Ivan-Luo/p/11150804.html
Copyright © 2020-2023  润新知