一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥0)个位置,即将A中的数据由(A0A1⋯AN−1)变换为(AN−M⋯AN−1A0A1⋯AN−M−1)(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?
输入格式:
每个输入包含一个测试用例,第1行输入N(1≤N≤100)和M(≥0);第2行输入N个整数,之间用空格分隔。
输出格式:
在一行中输出循环右移M位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。
输入样例:
6 2
1 2 3 4 5 6
输出样例:
5 6 1 2 3 4
思路:
本题算是一个典型的线性表操作的算法题,在不使用其他数组的前提下实现数组的整体右移可以通过使用三次翻转来实现。具体请看下面代码。
Dinger的代码:
#include<iostream>
#include<vector>
using namespace std;
int main() {
int N, M;
cin >> N >> M;
M = M%N;
vector<int> numbers(N);
for (int i = 0; i < N; i++) {
cin >> numbers[i];
}
for (int i = 0; i < (N - M) / 2; i++) {
int temp = numbers[i];
numbers[i] = numbers[N - M - i - 1];
numbers[N - M - i - 1] = temp;
}
for (int i = 0; i < M / 2; i++) {
int temp = numbers[N - M + i];
numbers[N - M + i] = numbers[N - i - 1];
numbers[N - i - 1] = temp;
}
for (int i = 0; i < N / 2; i++) {
int temp = numbers[i];
numbers[i] = numbers[N - i - 1];
numbers[N - i - 1] = temp;
}
for (int i = 0; i < N; i++) {
if (i) {
cout << " ";
}
cout << numbers[i];
}
}
其中要注意的一点是,题目并没有规定M<N,因此为了保证数组不发生越界,需要加上一句M = M % N;
。
网上用相同方法的博客有博客1、博客2、博客3。
其中第三篇直接使用了c++的库函数来实现数组倒置,减少了许多复杂的步骤,以后也可以用得上。
其他方法:
对于本题,其他博主也分享了一些其他的思路以及解题技巧
思路1:
本篇博客使用另外一个数组来存放循环右移后的数组,其实呢也是一种很好的方法,不过呢,可能这位博主并没有注意到题目不让使用其他数组,那本思路就不太适合这道题了。
思路2:
另一种主流的解法是直接“面向答案编程”,既然要输出循环右移后的元素,那就通过两个不同范围的输出循环达到相应的效果,好像是解出了这道题,又好像是没有解这道题~~~。不过呢,对于应试来说,也是值得学习的嘛!
可参考博客1、博客2、博客3、博客4
思路3:
思路3是该篇博客提出的,和思路2有些相似,都相当于“面向答案编程”,该思路是在输入数组的时候就根据右移位数在目标下标进行输入,这样输入完毕,该数组就是最终的数组了。
思路4:
该思路与上述方法都不尽相同,是完全贯彻了循环数组定义的算法(除了思路1)具体思路就是将元素循环整体右移,每次最右侧元素与第一个元素交换,这样就实现了循环右移的思想。
something else:
喜欢的小伙伴多多点赞关注哦,对博客内容有疑问或者有其他好的解法的小伙伴积极评论哦,我将持续更新见到的更加新颖更加高效的算法分享给大家,我们一起学习一起进步!