技术文章:实现德州扑克“葫芦”牌型的最大组合
问题背景
在德州扑克游戏中,“葫芦”是一种由五张牌组成的特殊牌型,其中包括三张相同牌面值的牌(记为a)和另外两张相同牌面值的牌(记为b)。若两位玩家的“葫芦”牌型相同,则通过比较a的大小来判断大小,若a相同,则通过b的大小来进一步比较。
在本题中,我们增加了一个约束条件,即组成“葫芦”的五张牌的牌面值之和不能超过给定的最大值max,并且牌面值的大小规则如下:
- A = 1
- K = 13
- Q = 12
- J = 11
- 10 = 10
- 9 = 9
- ...
- 2 = 2
我们的目标是从给定的牌面数组中,找到符合规则的最大“葫芦”组合,并输出其中三张相同的牌面和两张相同的牌面。如果无法找到符合条件的“葫芦”,则输出[0, 0]。
解决方案
-
统计每张牌的数量: 我们首先需要统计数组中每个牌面值出现的次数。这是通过一个大小为14的计数数组
cnt来完成的,其中cnt[i]表示牌面值为i的牌的数量。 -
遍历所有可能的三张相同牌面值和两张相同牌面值的组合: 对于每一个可能的三张相同牌面(记为a),我们遍历所有可能的两张相同牌面(记为b)。同时,我们需要满足以下两个条件:
- 牌a的数量必须大于或等于3。
- 牌b的数量必须大于或等于2,并且a和b不能相同。
-
计算“葫芦”的牌面值总和: 对于每一组a和b,我们计算它们的牌面值总和,并判断是否满足总和不超过给定的
max。如果符合条件,我们更新当前找到的“葫芦”牌型。 -
比较两个“葫芦”牌型的大小: 如果存在多个符合条件的“葫芦”牌型,我们需要通过牌a的大小来优先比较,若牌a相同,再通过牌b的大小来比较。
-
返回最大组合: 最后,我们返回找到的最大“葫芦”组合,若没有符合条件的“葫芦”,返回
[0, 0]。
代码实现
public static int[] solution(int n, int max, int[] array) {
int[] cnt = new int[14]; // 记录每种牌面出现的次数
for (int num : array) {
cnt[num] += 1; // 统计每个数字的出现次数
}
int maxA = 0; // 最大的三张相同牌面值
int maxB = 0; // 最大的两张相同牌面值
int sumOfHand = 0; // 当前最大的“葫芦”的总和
// 牌面值排序: A > K > Q > J > 10 > 9 > 8 > ... > 2
int[] cards = new int[] { 1, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 };
int[] value = new int[] { 15, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 }; // 对应的牌面值
// 遍历所有可能的三张相同牌面和两张相同牌面
for (int i = 0; i < cards.length; i++) {
int a = cards[i];
if (cnt[a] >= 3) { // 如果有三张a
for (int j = 0; j < cards.length; j++) {
int b = cards[j];
if (cnt[b] >= 2 && a != b) { // 如果有两张b,且a不等于b
int sumOfPoint = a * 3 + b * 2; // 计算牌面值的和
int sumOfNewHand = value[i] * 3 + value[j] * 2; // 根据优先规则计算新的牌面值
if (sumOfPoint <= max && sumOfNewHand > sumOfHand) { // 满足总和不超过max且找到更大的“葫芦”
if (a > maxA || (a == maxA && b > maxB)) { // 优先比较a,再比较b
maxA = a;
maxB = b;
sumOfHand = sumOfNewHand;
}
}
}
}
}
}
// 如果没有找到符合条件的“葫芦”,返回[0, 0]
return new int[] { maxA, maxB };
}
复杂度分析
-
时间复杂度:
- 统计每张牌出现的次数的时间复杂度是O(n),其中n是输入数组的长度。
- 遍历所有可能的牌面组合进行计算,总共要检查13种牌面值,所以这是常数级别的,可以视为O(1)。
因此,总的时间复杂度是O(n)。
-
空间复杂度:
- 需要一个大小为14的计数数组
cnt,所以空间复杂度是O(1)。
- 需要一个大小为14的计数数组
作者: AWM