【Day21】每日一题——洗牌

洗牌_牛客题霸_牛客网

它的意思是说,给你一份2n张的牌组,左手拿n张,右手拿n张,然后来进行洗牌操作

洗牌的操作是这样的,你的牌组假设是 1  2  3  4  5  6

那么你左手拿3张:1  2  3(第一张牌是1,最后一张牌是3)

右手也拿3张:4  5  6(第一张牌是4,最后一张牌是6)、

分好牌后,现在进行洗牌:先放右手的牌,先放最后一张(也就是6),然后再放左手的牌(同样是此时的最后一张:3)然后就按照每边都放此时的最后一张牌,然后右左交替即可

然后洗一遍牌后:结果为1  4  2  5  3  6(从第一张牌往下看的结果)

假如又要再洗一遍牌:那么要在上一次洗的牌的基础上来给左手右手分牌

左手此时就拿到了1  4  2

右手就拿到了:5  3  6

再次分好牌后,又继续往复上述的洗牌过程即可~

以上就是题目的规则介绍和基本思路


下面细说解题的法子~

1.首先我们要给一组牌组对吧(1  2  3  4  5  6),那么我们可以选择一个数组来定义这些元素,之后在给左手和右手各分配一半; 但是把因为我们既然要给左手和右手分配一半的牌,那么我们直接给左手数组和右手数组直接赋值就行了,两个数组的长度就是n

2.给左手右手分好牌后,我们就要来洗牌了,咱们直接自定义一个洗牌的方法(washCard)

我们来讲讲洗牌的代码实现

既然我们要左右手放牌,我们可以联想到栈,首先栈的特点是什么呢:先进后出对吧

我们画个图来理解,我们现在把左手和右手的牌各自从上到下放在栈里面

s1表示左手栈,s2表示右手栈,我们分别把左手右手元素push进去后,就上图所示~

我们根据栈后进先出的特点,分别把两个栈,依次右左弹出~

这时候我们再定义一个栈s3,我们把依次弹出的元素push到s3中,咱们根据要求来:先弹出右手的6,再弹出左手3,依次下来就是6  3  5  2  4  1

我们按照这个规则把弹出的元素依次存在s3中,我们会得到下图的s3~

 注意!!!!我们把s3搞出来后,你会发现,我们洗第一次牌的结果就是s3从上到下元素排序的结果!!!!

然后我们根据栈的特点依次把s3的元素弹出,我们可以把弹出的元素依次存在一个长度为2n的数组中,数组的结果就是  1  4  2  5  3  6

这样我们就完成了第一次洗牌!!!这不算难对吧?思路到这里是很清晰的~

那么我们再来看特殊情况:假如要洗多次牌呢?

咱们假设要洗2次吧(多次就是把洗牌的过程重复就行了)

我们已经洗好一次了,结果为 1  4  2  5  3  6 了对吧,因为这个结果是用一个数组存的,然后要在这个顺序的基础上再洗一次牌,接下来还是跟之前一样咯,给左手右手各自分一半的牌,这时候左手又拿到牌了:1  4  2       右手拿到:5  3  6

既然我们再次分好牌,只需要再来一遍上述洗牌的过程即可,再分别放在两个栈里面,然后再分别弹出到第3个栈,依次又从第三个栈弹出元素即可~~

下面是代码实现

import java.util.*;
import java.util.Stack;

public class Main {
     public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int group = in.nextInt();
        while (group > 0){
            int n = in.nextInt();
            int count = in.nextInt();
            int[] left = new int[n];
            int[] right = new int[n];
            for(int i = 0; i < n; i++){
                left[i] = in.nextInt();
            }
            for(int i = 0; i < n; i++){
                right[i] = in.nextInt();
            }
            washCard(left,right,count);
            group--;
        }

    }

    //洗牌方法
    public static void washCard(int[] left, int[] right, int count){
        Stack<Integer> s1 = new Stack<>();
        Stack<Integer> s2 = new Stack<>();
        int n = left.length;
        int[] ret = new int[2 * n];
        for(int j = 0; j < count; j++){
            //把left和right分别push进s1,s2
            for(int i = 0; i < n; i++){
                s1.push(left[i]);
            }
            for(int i = 0; i < n; i++){
                s2.push(right[i]);
            }
            Stack<Integer> s3 = new Stack<>();
            for(int i = 0; i < n; i++){
                s3.push(s2.pop());
                s3.push(s1.pop());
            }

            for(int i = 0; i < ret.length; i++){
                ret[i] = s3.pop();
            }

            //到这里说明洗完一次牌了,要重新给left 和 right 更新元素
            for(int i = 0; i < n; i++){
                left[i] = ret[i];
            }
            for (int i = 0; i < n; i++){
                right[i] = ret[n + i];
            }
        }
        for(int x : ret){
            System.out.print(x + " ");
        }
        System.out.println();
    }
}

 注意它要求的输入

先输入多少组数据group

然后在输入一边手拿的牌数和洗牌的次数

然后给依次给左手右手赋值n张牌就好了~

ok,结束~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值