豆包MarsCode AI 刷题

7 阅读5分钟

寻找最大葫芦

问题描述

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

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

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

问题分析

本题涉及到“葫芦”牌型的识别和最大值限制。在德州扑克中,葫芦是由三张相同面值的牌和两张相同面值的牌组成的牌型。我们需要在给定的一组牌中,寻找最大可能的葫芦组合,并且要求满足两点:

  1. 最大值限制:葫芦中的五张牌的面值总和不能超过给定的 max
  2. 牌面大小的排序:在找到多个符合条件的葫芦组合时,优先考虑“三张相同牌”的面值,若相同则再比较“两张相同牌”的面值。

牌面大小排序

题目中给定的牌面大小规则是:A > K > Q > J > 10 > 9 > ... > 2,其中 A 的牌面值为 1,K 为 13,依此类推。为了方便操作,我们将这些面值映射到数值上,便于计算和比较。也就是,面值的顺序从大到小排列,并赋予数值。

思路

  1. 牌的统计:首先,我们需要统计每种牌面值的出现次数。可以使用一个哈希表来记录每个牌面值的频次。
  2. 可能的三张牌和两张牌:根据统计信息,我们可以找出所有可能的三张相同牌和两张相同牌。每种面值的牌如果出现次数大于等于 3,就可以作为三张相同的牌;如果出现次数大于等于 2,就可以作为两张相同的牌。
  3. 过滤不合规的组合:遍历所有的三张牌和两张牌的组合,检查它们的总面值是否小于或等于 max。如果不符合条件,直接跳过。
  4. 选择最大组合:在所有合法的葫芦组合中,我们需要选择最大的组合,优先考虑“三张相同的牌”较大的组合,如果相同则考虑“两张相同的牌”。
  5. 返回结果:如果找到了符合条件的葫芦组合,返回该组合的牌面值;如果找不到,则返回 [0, 0]

代码解释

1. 统计每种牌的频次

我们使用一个 HashMap 来记录每种牌面值出现的次数。通过遍历给定的牌数组,将每张牌加入到 countMap 中,统计每种牌的数量。

java
Map<Integer, Integer> countMap = new HashMap<>();
for (int card : array) {
    countMap.put(card, countMap.getOrDefault(card, 0) + 1);
}

2. 寻找所有可能的三张牌和两张牌

根据每种牌的出现次数,我们将出现次数大于等于 3 的牌加入 possibleTriplets 列表,将出现次数大于等于 2 的牌加入 possiblePairs 列表。

java
List<int[]> possibleTriplets = new ArrayList<>();
List<int[]> possiblePairs = new ArrayList<>();

for (int card : countMap.keySet()) {
    int count = countMap.get(card);
    if (count >= 3) {
        possibleTriplets.add(new int[]{card, card, card});
    }
    if (count >= 2) {
        possiblePairs.add(new int[]{card, card});
    }
}

java

3. 计算所有合法的葫芦组合

然后,我们遍历所有可能的三张牌和两张牌组合。对于每一对三张牌和两张牌,我们检查它们的总面值是否小于等于 max。如果符合条件,则进一步比较组合的牌面值,选择最佳组合。

java
int[] bestTriplet = new int[]{0, 0, 0};
int[] bestPair = new int[]{0, 0};

for (int[] triplet : possibleTriplets) {
    for (int[] pair : possiblePairs) {
        if (triplet[0] != pair[0] && triplet[0] + triplet[1] + triplet[2] + pair[0] + pair[1] <= max) {
            if (triplet[0] > bestTriplet[0] || (triplet[0] == bestTriplet[0] && pair[0] > bestPair[0])) {
                bestTriplet = triplet;
                bestPair = pair;
            }
        }
    }
}

java

4. 返回结果

最后,如果我们找到了合适的葫芦组合,则返回三张牌和两张牌的面值;如果没有找到,返回 [0, 0]

java
if (bestTriplet[0] == 0) {
    return new int[]{0, 0};
} else {
    return new int[]{bestTriplet[0], bestPair[0]};
}

复杂度分析

  • 时间复杂度

    • 统计牌面值的频次需要遍历所有的牌,时间复杂度为 O(n),其中 n 是牌的数量。
    • 遍历所有可能的三张牌和两张牌的组合,最坏情况下我们需要对每个三张牌和两张牌组合进行遍历,时间复杂度是 O(k^2),其中 k 是不同牌面值的种类数。
    • 因此,整体时间复杂度为 O(n + k^2),在最坏情况下,k 可以达到 13(从 A 到 2)。
  • 空间复杂度

    • 我们使用了 HashMap 来统计牌面值的出现次数,空间复杂度是 O(k)k 是不同牌面值的种类数。
    • possibleTriplets 和 possiblePairs 列表的空间复杂度也是 O(k)

总结

这道题的关键在于正确理解“葫芦”的定义,并使用动态规划或贪心算法来选择最优组合。通过统计每种牌的频次并遍历可能的组合,可以有效地找到符合条件的最大葫芦组合。通过优先比较三张牌和两张牌的面值大小,我们可以确保选择的葫芦组合是最大的。如果没有符合条件的组合,则返回 [0, 0]