蓝桥杯---移动

  • 题目描述: 

“蓝桥杯”练习系统 (lanqiao.cn) 

资源限制

内存限制: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();
        }
    }

}

 (第一次发博客,两段代码本来是一起的被分开了,可能中途有点错,见谅😁,有错误欢迎指正哈,如果有不小心侵权的联系删除哈)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值