周一了,还是不能忘记提升自己的编程能力。
今天练习的这道题是PAT乙级1008,主要是为了解决数组元素循环向右问题,不看这道题目的具体描述,我就已经能猜出这道题的大概要求了。
就是为了让我们实现一组元素不停地向右移动。
比方说给定一组数据{1,2,3,4,5,6},向右移动两位的话,得到结果应该为{5,6,1,2,3,4}。
不过呢,为了保险起见,还是得看看这道题目的具体要求:
1、一个数组中存在N个整数,当然这里的N是大于0的,在不允许使用另外数组的前提下,将每个整数循环向右移M个位置,同时M也是大于0的。
2、第一行就是要输入N和M。
3、第二行呢就是要求输入N个整数。
例子:输入的N为6,M为2
第二行就要输入6个整数,比方说最简单的一些数1,2,3,4,5,6
这就意味着要循环右移两位,最后得到5,6,1,2,3,4
可以发现,5和6两个元素放在了最前面,而1和2两个元素往后移了两位。
很明显,这道题目的要求也很明确,M指的是右移多少位,N指的是输入多少个整数。
理清逻辑,画出流程图
当然,我的流程图仅仅只是逻辑方面的流程图,并不是代码的流程图。
在得到流程图之后,我们就要用代码来具体实现了。
代码实现逻辑
1、输入N和M,这不用多说,一个scanf足以搞定。
2、第二行输入N个整数,那就只需要写一个for循环进行遍历,然后把一个个整数给放进数组中去即可。
3、准备一个临时变量,因为题目中要求不能使用额外数组,但是呢,在做这道题目的过程中,会使得数组中的元素值发生变化,需要一个临时变量来赋值给变化的数组。
4、进行循环右移的逻辑实现,仔细想一下,要让{1,2,3,4,5,6} 变为{5,6,1,2,3,4},就是要发生一个数组中元素的变化,但难度并不在于前面的数往后挪动,主要难度在于最后面的两个数往前面挪动,因为一不小心就容易产生溢出的问题,所以这里的逻辑必须清楚。
5、最后的输出结果的结尾不能有多的空格,经过上次的经验教训,我已经发现了一种特别的方法,就是用计数法来输出空格,每次输出特定值的时候,count++,然后进行判断,如果count>0的话,就打印空格,这样就能确保序列结尾不存在空格了。
不过,我这里要着重强调一点:那就是循环右移的实现逻辑
从前到后的逻辑较为简单,只需要遍历数组然后把前面的数往后挪,后面的数与前面交换,但这里的问题就在于最后的元素怎么挪到前面来呢。
我们只需要让整个数组中的元素循环右移M位,所以这里第一个循环就应该以M为中心,小于M,毕竟数组的下标是从0开始的。
同时,因为我们要从最后一位元素进行分析,所以要先进行一个临时存储,把最后一个元素给存储下来,因为最后一位元素会发生变化,存储下来的话,可以把这个元素给放到前面去。
最后一位是N-1,所以下一个循环就要从N-1开始,并且不停地减1,直到数组中的第一个元素,也就是下标为0的元素。
这道题目我在做的时候,就是这里遇到了问题,但经过查阅资料,然后自己思考后就想明白了,既然是右移M位,那我只需要右移1位,然后移动M次不就可以了嘛。
在明白这个之后,我就知道接下来要怎么写了:
把最后一位给放到第一位,把倒数第二位放到最后一位,倒数第三位同理。
之后再进行M次循环,就能得到最终结果。
测试之后也正好出来自己想要的结果:
代码实现
#include<stdio.h>
int main(){
int N = 0;
int M = 0;
int out[100];
int Temp;
int count = 0;
scanf("%d %d", &N, &M);//第一行输入N和M
for(int i = 0; i < N; i++){
scanf("%d", &out[i]);
}
for(int i = 0; i < M; i++){//从前往后简单,从后往前难
Temp = out[N-1];
for(int j = N-1; j>=0; j--){
out[j] = out[j-1];
if(j==0){
out[j]=Temp;
}
}
}
for(int i = 0; i < N; i++){
if(count>0){
printf(" ");
}
printf("%d", out[i]);
count++;
}
}
PAT提交结果
总结
注意点:
1、序列结尾不能有多余空格。
2、在循环右移无法实现的时候,不妨可以拆分考虑,先考虑右移,再进行循环,每次只移动一次,然后循环M次。
总的来说,这道题目是特别考验数组的,对数组还要再加深理解才行。