寻找最大葫芦
问题描述
在一场经典的德州扑克游戏中,有一种牌型叫做“葫芦”。“葫芦”由五张牌组成,其中包括三张相同牌面值的牌 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)。
为了实现这一目标,我们可以使用以下步骤:
- 统计牌面值出现的频率:使用一个数组来记录每种牌在输入数组中出现的次数。
- 查找三条和对子:从高到低查找满足条件的牌面值,首先查找三条,然后查找可以组成的对子。
- 计算总和:在找到合理的组合后,计算它们的总和,并与
max进行比较。 - 输出结果:如果找到合适的葫芦,返回其牌面值;如果没有找到,返回
[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}));
}
}
关键部分解析
-
结果数组和计数数组的初始化:
int[] res = {0, 0}; // 用于存储最终的葫芦值 int[] count = new int[14]; // 用于统计牌面值的出现次数,索引0未使用 -
统计牌面值的出现次数:
for (int i = 0; i < n; i++) { count[array[i]]++; }这一部分循环遍历输入的牌数组,将每个牌面值的出现次数记录在
count数组中。 -
特殊处理数字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)出现至少三次,就将其设为三条。然后查找是否有其他牌可以作为对子。如果找到合适的组合,则返回结果。 -
查找三条和对子:
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作为对子)。 -
返回结果:
return new int[]{0, 0}; // 没有找到有效葫芦如果没有找到任何符合条件的葫芦组合,则返回
[0, 0]。
总结
这段代码通过统计和比较的方式,有效地找到了符合条件的最大葫芦组合。它的关键在于:
- 使用数组统计牌面值的出现次数。
- 从高到低查找三条和对应的对子,确保总和不超过
max。 - 处理特殊情况(比如
1),以确保逻辑的全面性。
这种实现方式在处理扑克游戏的相关问题时非常高效,能够快速找到所需的组合。