寻找最大葫芦
问题描述
在一场经典的德州扑克游戏中,有一种牌型叫做“葫芦”。“葫芦”由五张牌组成,其中包括三张相同牌面值的牌 aa 和另外两张相同牌面值的牌 bb。如果两个人同时拥有“葫芦”,我们会优先比较牌 aa 的大小,若牌 aa 相同则再比较牌 bb 的大小。
在这个问题中,我们对“葫芦”增加了一个限制:组成“葫芦”的五张牌牌面值之和不能超过给定的最大值 maxmax。牌面值的大小规则为:A > K > Q > J > 10 > 9 > ... > 2,其中 A 的牌面值为1,K 为13,依此类推。
给定一组牌,你需要找到符合规则的最大的“葫芦”组合,并输出其中三张相同的牌面和两张相同的牌面。如果找不到符合条件的“葫芦”,则输出 “0, 0”。
问题分析
本题涉及到“葫芦”牌型的识别和最大值限制。在德州扑克中,葫芦是由三张相同面值的牌和两张相同面值的牌组成的牌型。我们需要在给定的一组牌中,寻找最大可能的葫芦组合,并且要求满足两点:
- 最大值限制:葫芦中的五张牌的面值总和不能超过给定的
max
。 - 牌面大小的排序:在找到多个符合条件的葫芦组合时,优先考虑“三张相同牌”的面值,若相同则再比较“两张相同牌”的面值。
牌面大小排序
题目中给定的牌面大小规则是:A > K > Q > J > 10 > 9 > ... > 2,其中 A 的牌面值为 1,K 为 13,依此类推。为了方便操作,我们将这些面值映射到数值上,便于计算和比较。也就是,面值的顺序从大到小排列,并赋予数值。
思路
- 牌的统计:首先,我们需要统计每种牌面值的出现次数。可以使用一个哈希表来记录每个牌面值的频次。
- 可能的三张牌和两张牌:根据统计信息,我们可以找出所有可能的三张相同牌和两张相同牌。每种面值的牌如果出现次数大于等于 3,就可以作为三张相同的牌;如果出现次数大于等于 2,就可以作为两张相同的牌。
- 过滤不合规的组合:遍历所有的三张牌和两张牌的组合,检查它们的总面值是否小于或等于
max
。如果不符合条件,直接跳过。 - 选择最大组合:在所有合法的葫芦组合中,我们需要选择最大的组合,优先考虑“三张相同的牌”较大的组合,如果相同则考虑“两张相同的牌”。
- 返回结果:如果找到了符合条件的葫芦组合,返回该组合的牌面值;如果找不到,则返回
[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]
。