Question:
一个数组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
解决思路:数组循环移动是一种比较常见的问题,本题需要不借助另外的数组,并且要求移动次数较少,于是想起了考研数据结构中一种常见的解题思路:先将整体数组(下标0->数组末尾)reverse,然后将前半部分(从下标0->移动步数对应的下标)reverse,然后将后半部分(移动步数对应下标->数组末尾)
具体步骤:
具体如下,假设数组长度为6,循环右移2位,对应的步骤为
1.初始化数组:
1 2 3 4 5 6
2.整体reverse:
[ 6 5 4 3 2 1 ]
3.前半部分reverse:
[5 6] 4 3 2 1
4.后半部分reverse:
5 6 [ 1 2 3 4 ]
5.得到结果:
5 6 1 2 3 4
package PATC8;
import java.util.Scanner;
public class Main {
//翻转数组,从下标start->end
public static void reverse(Integer arr[],int start,int end)
{
int front=start,rear=end;
//System.out.println("(front:"+front+" rear:"+rear+")/2:"+(front+rear)/2);
for(int i=front;i<=(front+rear)/2;i++,end--)
{
//System.out.println("swap:["+arr[i]+"] and ["+arr[end]+"]");
int tmp=arr[i];
arr[i]=arr[end];
arr[end]=tmp;
}
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
//得到第一行数据
String num=sc.nextLine();
String[] split_num = num.split(" ");
//得到数组位数以及移动步数,这是个坑,容易忽略
int nums=Integer.parseInt(split_num[0]);
int steps=Integer.parseInt(split_num[1]);
//循环移动的步数可能会大于数组长度,因此取余就可以了
steps=steps%nums;
//得到第二行输入
Integer[] arr=new Integer[nums];
String arr_value=sc.nextLine();
String[] split_arr_value = arr_value.split(" ");
//初始化数组
for(int i=0;i<split_arr_value.length;i++)
{
arr[i]=Integer.parseInt(split_arr_value[i]);
}
//如果移动的步数为0,do nothing
if(steps==0)
{
//do nothing
}
//否则,不移动
else
{
//for(Integer i:arr)System.out.print(i+" ");System.out.println();
reverse(arr,0,nums-1);
//for(Integer i:arr)System.out.print(i+" ");System.out.println();
reverse(arr,0,steps-1);
//for(Integer i:arr)System.out.print(i+" ");System.out.println();
reverse(arr,steps,nums-1);
//for(Integer i:arr)System.out.print(i+" ");
}
//输出
for(int i=0;i<nums-1;i++)
{
System.out.print(arr[i]+" ");
}
System.out.print(arr[nums-1]);
}
}
补充:这个问题有个容易忽略的地方,就是因为是循环移动,移动的步数可能大于数组的长度,因此在操作之前先让其对长度取模,然后再翻转。此外,在翻转时还应该要考虑移动步数为0的情况,此时做一个简单的判断,让程序什么都不做即可。