问题描述
在一场经典的德州扑克游戏中,有一种牌型叫做“葫芦”。“葫芦”由五张牌组成,其中包括三张相同牌面值的牌 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
。
解题思路
-
统计牌面值:
- 创建一个长度为13的数组
count
,用于记录每种牌面值出现的次数。 - 遍历
array
,根据牌面值更新count
数组。
- 创建一个长度为13的数组
-
寻找三张相同牌面值的牌:
- 从最大的牌面值开始(K, 13),向下遍历到最小的牌面值(A, 1)。
- 检查
count
数组中每种牌面值的出现次数是否至少为3次,以确定是否可以作为“葫芦”中的三张相同牌面值的牌。
-
寻找两张相同牌面值的牌:
- 在找到三张相同牌面值的牌之后,继续遍历
count
数组,寻找可以作为“葫芦”中另外两张相同牌面值的牌的牌面值。 - 注意,这里需要跳过与三张相同牌面值的牌相同的牌面值。
- 在找到三张相同牌面值的牌之后,继续遍历
-
检查牌面值之和是否满足条件:
- 对于找到的每一对三张相同牌面值的牌和两张相同牌面值的牌,计算它们的牌面值之和。
- 如果牌面值之和小于或等于
max
,则记录下来。
-
输出结果:
- 如果找到了符合条件的“葫芦”牌型,则输出牌面值。
- 如果没有找到,则输出
[0, 0]
。
具体步骤:
- 初始化一个长度为13的数组
count
,用于统计每种牌面值的数量。 - 遍历输入的牌数组,更新
count
。 - 优先考虑A作为三张相同牌面值的牌,然后寻找两张相同牌面值的牌,检查牌面值之和是否不超过
max
。 - 如果上述步骤没有找到符合条件的牌型,则从K到2依次考虑每种牌面值作为三张相同牌面值的牌,然后寻找两张相同牌面值的牌,并检查牌面值之和。
- 如果找到了符合条件的牌型,则输出这两组牌面值;如果没有找到,则输出
[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}));
}
}
时间复杂度:
-
统计牌面值数量:
- 遍历整个牌数组
array
,其大小为n
。 - 这个操作的时间复杂度为 O(n)。
- 遍历整个牌数组
-
寻找三张相同牌面值的牌:
- 遍历
count
数组,其大小固定为 13。 - 这个操作的时间复杂度为 O(1),因为数组大小是常数。
- 遍历
-
寻找两张相同牌面值的牌:
- 在找到三张相同牌面值的牌之后,需要再次遍历
count
数组。 - 这个操作的时间复杂度也是 O(1)。
- 在找到三张相同牌面值的牌之后,需要再次遍历
由于 count
数组的大小是固定的,且与输入的牌的数量 n
无关,所以整个算法的时间复杂度主要取决于统计牌面值数量的步骤,即 O(n)。
空间复杂度:
-
count
数组:- 用于存储每种牌面值的数量,其大小为 13。
- 这个操作的空间复杂度为 O(1)。
-
输出数组:
- 输出数组的大小为 2,用于存储结果。
- 这个操作的空间复杂度为 O(1)。
综上所述,整个算法的空间复杂度为 O(1),因为它使用了固定大小的额外空间,与输入的牌的数量 n
无关。
总结:
- 时间复杂度:O(n)
- 空间复杂度:O(1)