-
题目描述:
资源限制
内存限制:256.0MB Java时间限制:3.0s
问题描述
给定一个n长的数列,有m次操作,第i次操作表示将整个数列循环移动mi位,询问每次操作结束后的开头k个数字
输入格式
第一行三个整数n,m,k。
第二行n个整数表示数列。
接下来m行,每行一个整数mi,表示移动位数,若mi为正,表示向左移mi位,若mi为负数,表示向右移-mi位。输出格式
m行,每行k个数,表示开头k个数字
样例输入
5 2 3
1 2 3 4 5
2
-2样例输出
3 4 5
1 2 3数据规模和约定
n<=1000000
m<=100000
k<=min(10,n)
mi<=100000000
-
坑🕳:
- 看到这道题目,其实和某一年的考研408数据结构真题很像,就想当然的用了下述的第一种方法,但是依题目说的数据规模不出意外的超时了!
- 移动值mi>数组大小n时,要%n(做题时忘了这回事)
- 向右移动时mi要转为+,不能简单绝对值处理。
-
思路1--用三次翻转完成(超时,测试时只能完成前四组样例):
- 左移:数组以(mi%n)为界,前(mi%n)个元素翻转一次,后(n-mi%n)个元素反转一次,最后集体翻转一次
- 右移:数组以(mi%n)为界,前(n-mi%n)个元素翻转一次,后(mi%n)个元素反转一次,最后集体翻转一次
package BlueBridge;
import java.util.Scanner;
public class Move {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] nums = new int[n];
int m = in.nextInt();
int k = in.nextInt();
int[] moves = new int[m];
for (int i = 0; i < nums.length; i++) {
nums[i] = in.nextInt();
}
for (int i = 0; i < moves.length; i++) {
moves[i] = in.nextInt();
}
methodOne(nums,moves,k);
in.close();
}
public static void methodOne(int[] nums, int[] moves, int k) { //超时
for (int i = 0; i < moves.length; i++) {
if (moves[i] < 0)
rightMove(nums, Math.abs(moves[i]) % nums.length);
else
leftMove(nums, moves[i] % nums.length);
for (int j = 0; j < k; j++) {
System.out.print(nums[j] + " ");
}
System.out.println();
}
}
public static void rightMove(int[] nums, int move) {
reverse(nums, 0, nums.length - move - 1);
reverse(nums, nums.length - move, nums.length - 1);
reverse(nums, 0, nums.length - 1);
}
public static void leftMove(int[] nums, int move) {
reverse(nums, 0, move - 1);
reverse(nums, move, nums.length - 1);
reverse(nums, 0, nums.length - 1);
}
public static void reverse(int[] nums, int s, int e) {
for (int i = s, j = e; i < j; i++, j--) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
这种方法时间复杂度会很大,按照这个数据规模是肯定会超时的,后来对代码不断改进以后还是超时了,后来也参考了一位博主(蓝桥杯算法训练-移动_天下一般的博客-CSDN博客_蓝桥杯移动)的文章以后,学会了他的思路,有了下面的代码
-
思路2:用起始游标的移动来模拟数组的转动。
- 首先标记数组输出的起始位置s(每次移动用这个来模拟)
- 然后对于数组左移mi时,相对应s向右走mi即可(注:会出现的一个问题就是>n,此时%n即可)
- 而数组右移mi时,相当于s向左走m即可(注:同样的s会出现<0的情况,此时一直加n直到>0为止)
package BlueBridge;
import java.util.Scanner;
public class Move {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] nums = new int[n];
int m = in.nextInt();
int k = in.nextInt();
int[] moves = new int[m];
for (int i = 0; i < nums.length; i++) {
nums[i] = in.nextInt();
}
for (int i = 0; i < moves.length; i++) {
moves[i] = in.nextInt();
}
methodTwo(nums, moves, k);
in.close();
}
public static void methodTwo(int[] nums, int[] moves, int k) { //答案方法
int s = 0; //标记数组输出的起始位置(每次移动用这个来模拟)
// 对于s的移动就两种情况 1.数组左移m时,相对应s向右(+)走m,会出现的一个问题就是>n,此时%n即可
// 2.数组右移m时,相当于s向左(-)走m,会出现<0,此时一直加n加到>0为止即可
for (int i = 0; i < moves.length; i++) {
s = (s + moves[i]) % nums.length;
while (s < 0)
s = (s + nums.length) % nums.length;
for (int j = 0; j < k; j++) {
System.out.print(nums[(s + j + nums.length) % nums.length] + " ");
}
System.out.println();
}
}
}
(第一次发博客,两段代码本来是一起的被分开了,可能中途有点错,见谅😁,有错误欢迎指正哈,如果有不小心侵权的联系删除哈)