试题 算法训练 移动 (Java实现)

问题描述
  给定一个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

思路:若是直接移动数组,对时间和空间的开销比较大,因为肯定要创建新数组来存储移动后的数据,这样是很不理想的,所以我们可以换一个思维,我们想象一个开始的索引,直接在原数组上移动索引,把这个索引的位置看作数组开头的位置,输出索引及其后面k个位置的数字就行。

但是又有两个问题,移动的距离加上原来的索引大于数组长度怎么办,该怎么移动,若索引加上移动的距离小于0,又怎么办?
这里不管左移动还是右移动,我们都让索引加上移动的距离,若是小于0,我们让它加n,直到大于0,若是大于n,则让他对n取模,因为不管左移还是右移,移动n位都相当于不移动,即移动n位肯定会回到原状态。

控制移动的代码:

	private static void act(int p){ //  移动的方法
        index += p;     //  移动后的索引位置
        while (index<0)
            index += n;  // 索引不能为负
        for (int i=0;i<k;i++){
            System.out.print(nums[(i+index)%n]+" ");    //  就从索引开始,往后共输出k个数
        }
        System.out.println();   //  控制输出格式
    }

p是当前传入的整数,例如若是-2,则是向右移2位,即开始索引变为(0-2+n)% n,即n-2。index是全局变量,初值为0。

然后呢,还需要注意一个问题,就是本题的数据规模很大,若是用Scanner,会超时,所以我们要用BufferedReader来读取输入流,本题我用BufferedReader才勉强通过100分。要真让我说BufferedReader和Scanner的区别我是真说不清楚,只有说在对于大规模数据处理的时候,BufferedReader的效率更高,若数据规模小,两者选择谁都没有影响。大家想深入了解它俩的区别的话,可以自行百度看看。

完整代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class 移动 {
    static int n,m,k;       //  定义n,m,k为全局变量,方便访问
    static int[] nums = new int[1000020];   //  数字数组
    static int[] orders = new int[100020];  //  执行移动命令的数组
    static int index = 0;       //  初始数组的开始位置,用移动开头索引的方式来替代移动数组,提高效率
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String[] s = reader.readLine().trim().split(" ");   //  存放n,m,k的值的数组
        n=Integer.parseInt(s[0]);   //  给n,m,k赋值(转化为整型)
        m=Integer.parseInt(s[1]);
        k=Integer.parseInt(s[2]);
        String[] s2 = reader.readLine().trim().split(" ");  //  获取数组中的各个数
        for (int i=0;i<n;i++)
            nums[i] = Integer.parseInt(s2[i]);  //  转化为整型
        for (int i=0;i<m;i++)
            orders[i] = Integer.parseInt(reader.readLine().trim()); //  接收移动的命令
        reader.close();     //  关闭输入流
        for (int i=0;i<m;i++)
            act(orders[i]);     //  执行移动
    }
    private static void act(int p){ //  移动的方法
        index += p;     //  移动后的索引位置
        while (index<0)
            index += n;  // 索引不能为负
        for (int i=0;i<k;i++){
            System.out.print(nums[(i+index)%n]+" ");    //  就从索引开始,往后共输出k个数
        }
        System.out.println();   //  控制输出格式
    }
}

蓝桥杯AC结果:
在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Easenyang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值