寻找最大葫芦 | 豆包MarsCode AI刷题

4 阅读5分钟

问题描述

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

在这个问题中,我们对“葫芦”增加了一个限制:组成“葫芦”的五张牌牌面值之和不能超过给定的最大值 maxmax。牌面值的大小规则为: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]

题目分析

题目要求我们在给定的牌中找到一个符合条件的“葫芦”牌型。葫芦牌型由三张相同牌面值的牌和两张相同牌面值的牌组成。同时,这五张牌的牌面值之和不能超过一个给定的最大值 max

解题思路

  1. 统计牌面值:

    • 创建一个长度为13的数组 count,用于记录每种牌面值出现的次数。
    • 遍历 array,根据牌面值更新 count 数组。
  2. 寻找三张相同牌面值的牌:

    • 从最大的牌面值开始(K, 13),向下遍历到最小的牌面值(A, 1)。
    • 检查 count 数组中每种牌面值的出现次数是否至少为3次,以确定是否可以作为“葫芦”中的三张相同牌面值的牌。
  3. 寻找两张相同牌面值的牌:

    • 在找到三张相同牌面值的牌之后,继续遍历 count 数组,寻找可以作为“葫芦”中另外两张相同牌面值的牌的牌面值。
    • 注意,这里需要跳过与三张相同牌面值的牌相同的牌面值。
  4. 检查牌面值之和是否满足条件:

    • 对于找到的每一对三张相同牌面值的牌和两张相同牌面值的牌,计算它们的牌面值之和。
    • 如果牌面值之和小于或等于 max,则记录下来。
  5. 输出结果:

    • 如果找到了符合条件的“葫芦”牌型,则输出牌面值。
    • 如果没有找到,则输出 [0, 0]

具体步骤:

  1. 初始化一个长度为13的数组 count,用于统计每种牌面值的数量。
  2. 遍历输入的牌数组,更新 count
  3. 优先考虑A作为三张相同牌面值的牌,然后寻找两张相同牌面值的牌,检查牌面值之和是否不超过 max
  4. 如果上述步骤没有找到符合条件的牌型,则从K到2依次考虑每种牌面值作为三张相同牌面值的牌,然后寻找两张相同牌面值的牌,并检查牌面值之和。
  5. 如果找到了符合条件的牌型,则输出这两组牌面值;如果没有找到,则输出 [0, 0]

代码实现

public class Main {
    public static int[] solution(int n, int max, int[] array) {
        // 统计每种牌面值的数量
        int[] count = new int[13];
        for (int card : array) {
            count[card - 1]++;
        }

        // 优先考虑A作为三张相同牌面值的牌
        if (count[0] >= 3) {
            count[0] -= 3;
            for (int j = 12; j >= 1; j--) { // 不考虑A作为两张相同牌面值的牌
                if (count[j] >= 2) {
                    // 找到了两张相同牌面值的牌
                    if (3 + (j + 1) * 2 <= max) {
                        return new int[]{1, j + 1};
                    }
                }
            }
            // 恢复计数器
            count[0] += 3;
        }

        // 从最大的牌面值开始寻找“葫芦”组合
        for (int i = 12; i >= 1; i--) { // 不考虑A作为三张相同牌面值的牌
            if (count[i] >= 3) {
                // 找到了三张相同牌面值的牌
                count[i] -= 3;
                if(count[0] >= 2) {
                    if ((i + 1) * 3 + 2 <= max) {
                        return new int[]{i + 1, 1};
                    }
                }
                for (int j = 12; j >= 0; j--) {
                    if (count[j] >= 2) {
                        // 找到了两张相同牌面值的牌
                        if ((i + 1) * 3 + (j + 1) * 2 <= max) {
                            return new int[]{i + 1, j + 1};
                        }
                    }
                }
                // 恢复计数器
                count[i] += 3;
            }
        }

        // 没有找到符合条件的“葫芦”组合
        return new int[]{0, 0};
    }

    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}));
    }
}

时间复杂度:

  1. 统计牌面值数量:

    • 遍历整个牌数组 array,其大小为 n
    • 这个操作的时间复杂度为 O(n)。
  2. 寻找三张相同牌面值的牌:

    • 遍历 count 数组,其大小固定为 13。
    • 这个操作的时间复杂度为 O(1),因为数组大小是常数。
  3. 寻找两张相同牌面值的牌:

    • 在找到三张相同牌面值的牌之后,需要再次遍历 count 数组。
    • 这个操作的时间复杂度也是 O(1)。

由于 count 数组的大小是固定的,且与输入的牌的数量 n 无关,所以整个算法的时间复杂度主要取决于统计牌面值数量的步骤,即 O(n)。

空间复杂度:

  1. count 数组:

    • 用于存储每种牌面值的数量,其大小为 13。
    • 这个操作的空间复杂度为 O(1)。
  2. 输出数组:

    • 输出数组的大小为 2,用于存储结果。
    • 这个操作的空间复杂度为 O(1)。

综上所述,整个算法的空间复杂度为 O(1),因为它使用了固定大小的额外空间,与输入的牌的数量 n 无关。

总结:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)