PAT (Basic Level) Practice 1008 数组元素循环右移问题

题目

一个数组 A A A 中存有 N ( > 0 ) N(>0) N>0个整数,在不允许使用另外数组的前提下,将每个整数循环向右移 M ( ≥ 0 ) M(≥0) M0个位置,即将A中的数据由 ( A 0 A 1 ⋅ ⋅ ⋅ A N − 1 ) ({A_0}{A_1} \cdot \cdot \cdot {A_{N - 1}}) (A0A1AN1)变换为 ( A N − M ⋅ ⋅ ⋅ A N − 1 A 0 ⋅ ⋅ ⋅ A N − M − 1 ) ({A_{N - M}} \cdot \cdot \cdot {A_{N - 1}}{A_0} \cdot \cdot \cdot {A_{N - M - 1}}) (ANMAN1A0ANM1)(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?

输入格式:

每个输入包含一个测试用例,第1行输入 N ( 1 ≤ N ≤ 100 ) N(1≤N≤100) N1N100 M ( ≥ 0 ) M(≥0) M0;第2行输入 N N N个整数,之间用空格分隔。

输出格式:

在一行中输出循环右移 M M M位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。

输入样例:

6 2
1 2 3 4 5 6

输出样例:

5 6 1 2 3 4

思路1(2020-4-10 14:44:49)

你说不用多余数组我就不用?那我不是很没面子?
我要是用了然后你卡我内存那我就更没面子了。。。
不用就不用,谁爱用谁用。反正你不检查我代码,我这样搞,你有脾气吼~
这个答案实在是,阴险狡诈。

答案1(2020-4-10 13:34:49)

#include <iostream>
using namespace std; 
int main(int argc, char** argv) {
	int n;
	int moveL;
	cin >> n;
	cin >> moveL;
	int arr[n];
	for(int i = 0 ; i < n; i++)
		cin >> arr[i];
		
	// I don't like move even once,output directly
	for(int i = n - (moveL % n) ; i < n ; i++) // if int i = n - moveL then 2 test point fail
	 	cout << arr[i] << " ";	
	cout << arr[0] ;
	for(int i = 1 ; i < n - (moveL % n); i++)
		cout << " " << arr[i] ;
	
	return 0;
}

思路2(2020-4-10 15:11:21)

既然是学习,就不要太,投机取巧了。
乖乖做题。
思路是,从第一个数往后挪,被挪到的也依次往后挪,直到挪到重合原来的位置,再接着挪下一个。或者挪到挪动次数等于数组大小,就不挪了。
例子1:

  1. 输入 1 , 2 , 3 , 4 , 5 , 6 1,2,3,4,5,6 1,2,3,4,5,6 往右挪2个位置,
  2. 从第1个位置的数开始,把第1个位置的数挪到第3个位置,第3个位置的数先找个地方放着,结果是
    1 , 2 , 1 , 4 , 5 , 6 , ( t e m p = 3 ) 1,2,1,4,5,6, (temp =3) 1,2,1,4,5,6,(temp=3)
  3. 然后再安排原来第3个位置的数,把第3个位置的数挪到第5个位置,第5个位置的数先找个地方放着,结果是
    1 , 2 , 1 , 4 , 3 , 6 , ( t e m p = 5 ) 1,2,1,4,3,6,(temp=5) 1,2,1,4,3,6,(temp=5)
  4. 然后再安排原来第5个位置的数,把第5个位置的数挪到第1个位置,和起点重复,直接挪进去结果是
    5 , 2 , 1 , 4 , 3 , 6 5,2,1,4,3,6 5,2,1,4,3,6
  5. 接着挪下一个,从第2个位置的数开始,把第2个位置的数挪到第4个位置,第4个位置的数先找个地方放着,结果是
    5 , 2 , 1 , 2 , 3 , 6 ( t e m p = 4 ) 5,2,1,2,3,6 (temp =4) 5,2,1,2,3,6(temp=4)
  6. 然后再安排原来第4个位置的数,把第4个位置的数挪到第6个位置,第6个位置的数先找个地方放着,结果是
    5 , 2 , 1 , 2 , 3 , 4 ( t e m p = 6 ) 5,2,1,2,3,4 (temp =6) 5,2,1,2,3,4(temp=6)
  7. 然后再安排原来第6个位置的数,把第6个位置的数挪到第2个位置,和起点重复,直接挪进去结果是
    5 , 6 , 1 , 2 , 3 , 4 5,6,1,2,3,4 5,6,1,2,3,4
  8. 总共挪了6次了,移动结束,输出。

例子2:

  1. 输入 1 , 2 , 3 , 4 , 5 , 6 , 7 1,2,3,4,5,6,7 1,2,3,4,5,6,7 往右挪4个位置,
  2. 从第1个位置的数开始,把第1个位置的数挪到第5个位置,第5个位置的数先找个地方放着,结果是
    1 , 2 , 3 , 4 , 1 , 6 , 7 , ( t e m p = 5 ) 1,2,3,4,1,6,7, (temp =5) 1,2,3,4,1,6,7,(temp=5)
  3. 然后再安排原来第5个位置的数,把第5个位置的数挪到第2个位置,第2个位置的数先找个地方放着,结果是
    1 , 5 , 3 , 4 , 1 , 6 , 7 , ( t e m p = 2 ) 1,5,3,4,1,6,7,(temp=2) 1,5,3,4,1,6,7,(temp=2)
  4. 然后再安排原来第2个位置的数,把第2个位置的数挪到第6个位置,第6个位置的数先找个地方放着,结果是
    1 , 5 , 3 , 4 , 1 , 2 , 7 , ( t e m p = 6 ) 1,5,3,4,1,2,7,(temp=6) 1,5,3,4,1,2,7,(temp=6)
  5. 然后再安排原来第6个位置的数,把第6个位置的数挪到第3个位置,第3个位置的数先找个地方放着,结果是
    1 , 5 , 6 , 4 , 1 , 2 , 7 ( t e m p = 3 ) 1,5,6,4,1,2,7 (temp =3) 1,5,6,4,1,2,7(temp=3)
  6. 然后再安排原来第3个位置的数,把第3个位置的数挪到第7个位置,第7个位置的数先找个地方放着,结果是
    1 , 5 , 6 , 4 , 1 , 2 , 3 ( t e m p = 7 ) 1,5,6,4,1,2,3 (temp =7) 1,5,6,4,1,2,3(temp=7)
  7. 然后再安排原来第7个位置的数,把第7个位置的数挪到第4个位置,第4个位置的数先找个地方放着,结果是
    1 , 5 , 6 , 7 , 1 , 2 , 3 ( t e m p = 4 ) 1,5,6,7,1,2,3 (temp =4) 1,5,6,7,1,2,3(temp=4)
  8. 然后再安排原来第4个位置的数,把第4个位置的数挪到第1个位置,和起点重复,直接挪进去结果是
    4 , 5 , 6 , 7 , 1 , 2 , 3 4,5,6,7,1,2,3 4,5,6,7,1,2,3
  9. 总共挪了7次了,移动结束,输出。

答案2 (2020-4-10 14:29:09)

 #include <iostream>
using namespace std; 
int main(int argc, char** argv) {
	int n;
	int moveL;
	cin >> n;
	cin >> moveL;
	int arr[n];
	for(int i = 0 ; i < n; i++)
		cin >> arr[i];
	
	int changetimes = 0;		
	//moving
	for(int i = 0 ; i < (moveL % n) ; i++) 
	{
		if(changetimes >= n)
			break;
		int step = ( moveL % n );
		int toBeChangeIndex = (i + step) % n ;
		int temp = arr[i];
		int temp2;
		while(toBeChangeIndex != i){		
			//swap arr[toBeChangeIndex] with temp
			temp2 = arr[toBeChangeIndex];
			arr[toBeChangeIndex]= temp;
			temp = temp2;
			
			changetimes ++;
			toBeChangeIndex =  (toBeChangeIndex + step) %n ;
		}
		arr[i] = temp;
		changetimes ++;
	}
	
	cout << arr[0];	
	for(int j = 1 ; j < n; j++)
		cout << " " << arr[j] ;

	return 0;
}

思路3 (2020-4-10 15:22:11)

写完博客信心满满去百度看其他dalao,我就又泪流满面的回来了。
其实就是要把一个数组1234abcd,给变成abcd1234,假如把前边当成一个整体a,把后边当成一个整体A,就是要把aA翻成Aa,但是直接翻1234abcd会变成dcba4321,a和A内部颠倒了,那就再把内部也翻一下就好了。
这个思路之前复习的时候有看到过,我怎么就给忘了呢,辛辛苦苦敲了半天的码和博客,一文不值,emmmmm。

答案3(2020-4-10 15:46:27)

无敌一般的存在,给我学!

#include <iostream>
using namespace std;

//reverse array arr between index a and b ,include swap a,b
//a<b
void reverse(int arr[], int a , int b)
{
	int temp;
	int j = b;
	for(int i = a; i < (b - a + 1) / 2 + a ; i++)
	{
		temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
		j--;	
	}
}

int main(int argc, char** argv) {
	int n,moveL;
	cin >> n >> moveL;
	int arr[n];
	for(int i = 0 ; i < n ; i++)
		cin >> arr[i];
	
	moveL = moveL % n;
	reverse(arr,0,n-1);
	reverse(arr , 0 , moveL - 1);
	reverse(arr , moveL,n-1);
	
	cout << arr[0];
	for(int i = 1 ; i < n ; i++)
		cout << " " << arr[i] ;
	cout << endl;
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值