浙大PAT乙级 B1008 数组元素循环右移问题

14 篇文章 0 订阅

PAT - B1008 数组元素循环右移问题(20分) https://pintia.cn/problem-sets/994805260223102976/problems/994805316250615808
题目

大致思路:
  • 自己的错误思路:按移动位数 M 将数据分组,每组每个元素循环右移 M 位(在所在组中相当于只右移一位)。
  • 暴力法(实测可以通过):每次循环右移一位,进行M次。
  • 《算法笔记》方法:从N - M位开始枚举,直至N - M + d - 1位截止(其中 d 为 N 和 M 的最大公约数;取此值的目的是避免重复移动元素,数学原理不清楚…)。对于枚举的每个位置,用指针逆向向前走(循环),以 M 为间隔将“逐个”元素循环右移“一”位,直到指针回到初始位置时停止。
通过代码(C/C++):
#include<stdio.h>
int gcd(int a, int b)   {   return b==0 ? a : gcd(b, a%b);    } //求最大公约数

int main(){
	int N, M;
	scanf("%d %d", &N, &M);
	int a[100];
	for(int i=0;i<N;i++)    scanf("%d", a+i);
	M = M % N;  // M可能大于N,做修正

/* 自己的高时间复杂度做法:每次循环右移一位,进行M次
	for(int i=0;i<M;i++){
        int temp=a[N-1];
        for(int j=N-1;j>0;j--){
            a[j]=a[j-1];
        }
        a[0]=temp;
	}
*/

// 算法笔记解法:
    if(M!=0){   //M=0时不用、也不能进入下面循环,直接进行后续输出
        int i_end = N - M + gcd(N, M);  //枚举的截止位下标(数学原理?),避免重复移动元素
        for(int i=N-M;i<i_end;i++){
            int pos=i, temp=a[i];
            do{ //以M为间隔将各元素循环右移“一”位,直到指针回到初始位置
                int next=(pos-M+N)%N;
                a[pos] = next==i ? temp : a[next];
                pos=next;
            }while(pos!=i);
        }
    }
//

	printf("%d", a[0]);
    for(int i=1;i<N;i++)  printf(" %d",a[i]);
	return 0;
}


/*自己的早先错误做法,对于以下数据处理不正确(但通过了题目……)
8 3
1 2 3 4 5 6 7 8

#include<stdio.h>
int main(){
	int N, M;
	scanf("%d %d", &N, &M);
	int a[100];
	for(int i=0;i<N;i++)    scanf("%d", a+i);
	M = M % N;  // M可能大于N,做修正
	for(int i=0;i<M;i++){
        int temp = a[i];    //暂存每次逆向循环第一个元素值
        int j;
        for(j=(i-M+N)%N;j>i;j-=M){  // 逆向循环移动一遍,间隔M
            a[(j+M)%N] = a[j];
        }
        a[j+M] = temp;  //本次循环最后一个元素
	}
	printf("%d", a[0]);
    for(int i=1;i<N;i++)  printf(" %d",a[i]);
	return 0;
}
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值