青训营X豆包MarsCode 技术训练营第二课_寻找最大葫芦

397 阅读5分钟

寻找最大葫芦

问题描述

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

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

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


测试样例

样例1:

输入:n = 9, max = 34, array = [6, 6, 6, 8, 8, 8, 5, 5, 1] 输出:[8, 5]

样例2:

输入:n = 9, max = 37, array = [9, 9, 9, 9, 6, 6, 6, 6, 13] 输出:[6, 9]

样例3:

输入:n = 9, max = 40, array = [1, 11, 13, 12, 7, 8, 11, 5, 6] 输出:[0, 0]

算法思路

在德州扑克中,牌面值的大小规则如下:

  • A(1) > K(13) > Q(12) > J(11) > 10 > 9 > ... > 2 这意味着 A 被视为最小的牌,而 K 是最大的一张牌。我们的目标是找到一组符合条件的葫芦,并输出其中三张相同的牌面(a)和两张相同的牌面(b)。

为了实现这一目标,我们可以使用以下步骤:

  1. 统计牌面值出现的频率:使用一个数组来记录每种牌在输入数组中出现的次数。
  2. 查找三条和对子:从高到低查找满足条件的牌面值,首先查找三条,然后查找可以组成的对子。
  3. 计算总和:在找到合理的组合后,计算它们的总和,并与 max 进行比较。
  4. 输出结果:如果找到合适的葫芦,返回其牌面值;如果没有找到,返回 [0, 0]

代码概述

这段代码的目的是在给定的牌组中寻找最大的“葫芦”组合,满足的条件是:

  • 三张相同的牌(称为 a
  • 两张相同的牌(称为 b
  • 牌面值的和不能超过指定的最大值 max

代码结构

public class Main {
    public static int[] solution(int n, int max, int[] array) {
        int[] res = {0, 0}; // 初始化结果数组
        int[] count = new int[14]; // 统计牌面值出现的频率
        
        // 统计每种牌面值的出现次数
        for (int i = 0; i < n; i++) {
            count[array[i]]++;
        }
        
        // 特殊处理数字1
        if (count[1] >= 3) {
            res[0] = 1; // 设定三条为1
            for (int j = 13; j >= 2; j--) {
                if (count[j] >= 2 && (3 * 1 + 2 * j) <= max) {
                    res[1] = j; // 找到合适的对子
                    return res; // 返回结果
                }
            }
        }

        // 从高到低查找三条
        for (int i = 13; i >= 2; i--) {
            if (count[i] >= 3) {
                res[0] = i; // 找到三条
                // 检查是否可以用1作为对子
                if (count[1] >= 2 && (3 * i + 2 * 1) <= max) {
                    res[1] = 1; // 找到合适的对子
                    return res; // 返回结果
                }
                // 查找其他可能的对子
                for (int j = 13; j >= 1; j--) {
                    if (i != j && count[j] >= 2 && (3 * i + 2 * j) <= max) {
                        res[1] = j; // 找到合适的对子
                        return res; // 返回结果
                    }
                }
            }
            res[0] = 0; // 重置三条为0
        }
        return new int[]{0, 0}; // 没有找到有效葫芦
    }

    public static void main(String[] args) {
        // 测试用例
        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(java.util.Arrays.equals(solution(31, 42, new int[]{3, 3, 11, 12, 12, 2, 13, 5, 13, 1, 13, 8, 8, 1, 8, 13, 12, 9, 2, 11, 3, 5, 8, 11, 1, 11, 1, 5, 4, 2, 5}), new int[]{1, 13}));
        System.out.println(java.util.Arrays.equals(solution(44, 36, new int[]{10, 11, 6, 13, 9, 7, 6, 2, 2, 2, 4, 10, 4, 3, 3, 7, 2, 4, 5, 11, 12, 10, 7, 9, 5, 13, 8, 1, 6, 9, 3, 8, 10, 11, 5, 3, 7, 11, 1, 8, 4, 5, 9, 6}), new int[]{11, 1}));
    }
}

关键部分解析

  1. 结果数组和计数数组的初始化

    int[] res = {0, 0}; // 用于存储最终的葫芦值
    int[] count = new int[14]; // 用于统计牌面值的出现次数,索引0未使用
    
  2. 统计牌面值的出现次数

    for (int i = 0; i < n; i++) {
        count[array[i]]++;
    }
    

    这一部分循环遍历输入的牌数组,将每个牌面值的出现次数记录在 count 数组中。

  3. 特殊处理数字1

    if (count[1] >= 3) {
        res[0] = 1; // 设定三条为1
        for (int j = 13; j >= 2; j--) {
            if (count[j] >= 2 && (3 * 1 + 2 * j) <= max) {
                res[1] = j; // 找到合适的对子
                return res; // 返回结果
            }
        }
    }
    

    如果数字 1(A)出现至少三次,就将其设为三条。然后查找是否有其他牌可以作为对子。如果找到合适的组合,则返回结果。

  4. 查找三条和对子

    for (int i = 13; i >= 2; i--) {
        if (count[i] >= 3) {
            res[0] = i; // 找到三条
            // 检查是否可以用1作为对子
            if (count[1] >= 2 && (3 * i + 2 * 1) <= max) {
                res[1] = 1; // 找到合适的对子
                return res; // 返回结果
            }
            // 查找其他可能的对子
            for (int j = 13; j >= 1; j--) {
                if (i != j && count[j] >= 2 && (3 * i + 2 * j) <= max) {
                    res[1] = j; // 找到合适的对子
                    return res; // 返回结果
                }
            }
        }
        res[0] = 0; // 重置三条为0
    }
    

    该部分从高到低查找三条。如果找到三条,则继续检查是否可以找到符合条件的对子(包括 1 作为对子)。

  5. 返回结果

    return new int[]{0, 0}; // 没有找到有效葫芦
    

    如果没有找到任何符合条件的葫芦组合,则返回 [0, 0]

总结

这段代码通过统计和比较的方式,有效地找到了符合条件的最大葫芦组合。它的关键在于:

  • 使用数组统计牌面值的出现次数。
  • 从高到低查找三条和对应的对子,确保总和不超过 max
  • 处理特殊情况(比如 1),以确保逻辑的全面性。

这种实现方式在处理扑克游戏的相关问题时非常高效,能够快速找到所需的组合。