简单题总结2 | 豆包MarsCode AI刷题

47 阅读5分钟

问题描述

在一场经典的德州扑克游戏中,有一种牌型叫做“葫芦”。“葫芦”由五张牌组成,其中包括三张相同牌面值的牌 aa 和另外两张相同牌面值的牌 bb。如果两个人同时拥有“葫芦”,我们会优先比较牌 aa 的大小,若牌 aa 相同则再比较牌 bb 的大小。

在这个问题中,我们对“葫芦”增加了一个限制:组成“葫芦”的五张牌牌面值之和不能超过给定的最大值 maxmax。牌面值的大小规则为:A > K > Q > J > 10 > 9 > ... > 2,其中 A 的牌面值为1,K 为13,依此类推。

给定一组牌,你需要找到符合规则的最大的“葫芦”组合,并输出其中三张相同的牌面和两张相同的牌面。如果找不到符合条件的“葫芦”,则输出 “0, 0”。

解题思路

首先,也是最重要的一点,就是理解题目,并且要注意题目中的关键点。在这个题目中有两个关键点需要注意,第一个是它的面值中,面值为1的牌是最大的,其余的牌可按按面值大小排序。第二点是它有面值最大值的限制,即选定不能超过这个面值最大值的葫芦牌的组合。因此,要解决这个题目,思路就是先找出出现次数在三次及以上的数据和出现两次及以上的数据,然后再找出不会超过最大值的面值之和最大的组合。

解题代码

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Arrays;
public class Main {
    public static int[] solution(int n, int max, int[] array) {
        // Edit your code here
        int[] result = new int[2];
        //存放每个数字及其对应出现的次数
        Map<Integer,Integer> tmp = new HashMap<>();
        //出现三次及以上的数
        List<Integer> tmpA = new ArrayList<>();
        //出现两次及以上的数
        List<Integer> tmpB = new ArrayList<>();

        //遍历数据构造上面的各个容器
        for(int i=0;i<n;i++){
            if(!tmp.containsKey(array[i])){
                tmp.put(array[i],1);
            }else{
                tmp.put(array[i],tmp.get(array[i])+1);
                //因为1比较特殊,它的面值最大,为了方便比较,所以在放入的时候直接把1换成14
                if(array[i] == 1){
                    if(!tmpA.contains(14) && tmp.get(array[i]) >= 3){
                        tmpA.add(14);
                    }
                    if(!tmpB.contains(14) && tmp.get(array[i]) >= 2){
                        tmpB.add(14);
                    }
                }else{
                    if(!tmpA.contains(array[i]) && tmp.get(array[i]) >= 3){
                        tmpA.add(array[i]);
                    }
                    if(!tmpB.contains(array[i]) && tmp.get(array[i]) >= 2){
                        tmpB.add(array[i]);
                        
                    }
                }      
                
            }
        }
        
        //对面值排序
        Collections.sort(tmpA);
        Collections.sort(tmpB);
        System.out.println(tmpA);
        System.out.println(tmpB);
        int i = tmpA.size() - 1;
        //从后往前遍历出现三次及以上的数据
        while(i>=0){
            int a = 0;
            //因为面值比较又需要原来的值,所以额外增加a,b两个变量来存储面值
            if(tmpA.get(i) == 14){
                a = 1;
            }else{
                a = tmpA.get(i);
            }
            if(a*3 > max){
                i--;
                continue;
            }
            //选择出现三次及以上的数据后,再选择出现两次及以上的数据
            for(int j=tmpB.size()-1;j>=0;j--){
                if(tmpA.get(i) == tmpB.get(j)){
                    continue;
                }
                int b = 0;
                if(tmpB.get(j) == 14){
                    b = 1;
                }else{
                    b = tmpB.get(j);
                }
                //有面值约束
                if(a*3 + b*2 <= max){
                    //比较面值的时候,因为结果中存的是原始面值,所以要处理一下
                    if(result[0] == 1){
                        if(tmpA.get(i)*3 + tmpB.get(j)*2 > 14*3 + result[1]*2){
                            result[0] = a;
                            result[1] = b;
                        }
                    }else if(result[1] == 1){
                        if(tmpA.get(i)*3 + tmpB.get(j)*2 > 14*3 + 14*2){
                            result[0] = a;
                            result[1] = b;
                        }
                    }else{
                        if(a*3 + b*2 > result[0]*3 + result[1]*2){
                            result[0] = a;
                            result[1] = b;
                        }
                    }
                    return result;
                }
            }
            i--;
        }  
        return result;
    }

    public static void main(String[] args) {
        // Add your test cases here
        System.out.println(java.util.Arrays.equals(solution(9, 34, new int[]{6, 6, 6, 8, 8, 8, 5, 5, 1}), new int[]{8, 5}));
        System.out.println(java.util.Arrays.equals(solution(9, 37, new int[]{9, 9, 9, 9, 6, 6, 6, 6, 13}), new int[]{6, 9}));
        System.out.println(java.util.Arrays.equals(solution(9, 40, new int[]{1, 11, 13, 12, 7, 8, 11, 5, 6}), new int[]{0, 0}));
        //System.out.println(Arrays.toString(solution(31, 17, new int[]{11,10,8,1,2,9,13,1,10,6,8,2,9,7,2,9,8,10,9,3,7,13,7,1,1,5,12,10,12,2,5})));
    }
}

总结

这个问题给我一个很大的教训就是要看清题目。一开始没有注意到题目中面值大小的设置,导致查了很久就找不出问题出在哪。还有一个就是可以根据结果看一些题目没有明说的条件,比如在这个题目中,只有两种及以上的出现三次及以上的牌,是否算作葫芦牌。题目没有明说,通过看解答可以看出是属于的。因此有时候要根据题目和给出的解答才能充分理解题意。

刷题心得总结

对目前利用MarsCode的刷题路程做个总结,在简单题中,也还是有难度区分的,有些简单题目一眼就知道怎么做,简单的穷举遍历就可以实现。有些简单题目具体实现不难,但是思路和理解题意很重要,一不小心就可能漏掉条件,而导致无法通过所有实例。还有一些简单题难度偏高,主要是解题思路比较巧妙或者比较复杂,同时还要考虑多种情况下的不同应对策略。中等题就侧重于解题思路和算法,要求在充分理解题意的基础上选择合适的合适的算法操作,比如贪心、动态规划、回溯等等。难题在中等题考察的基础上还注重对数据结构的考察比如队列和栈的用途等。总的来说,刷题技巧还是有所长进,同时也有很好的锻炼思维逻辑能力,希望在后面的刷题过程里进步更多。