一、题目分析
本题设定在德州扑克游戏的背景下,聚焦于一种特殊牌型 ——“葫芦”。正常 “葫芦” 由五张牌构成,包含三张相同牌面值的牌 a 和另外两张相同牌面值的牌 b,并且在本题中有两人同时拥有 “葫芦” 时比较大小的规则设定。但更为关键的是,本题给 “葫芦” 增加了一个额外限制,即组成 “葫芦” 的五张牌牌面值之和不能超过给定的最大值 max。同时明确了牌面值大小的规则,如 A(牌面值为 1)>K(牌面值为 13)>Q>J>10>9>...>2。最终任务是给定一组牌,从中找出符合上述规则的最大的 “葫芦” 组合,并输出其中三张相同的牌面和两张相同的牌面,如果找不到符合条件的 “葫芦”,则输出 [0, 0]。
二、解题思路探讨
-
统计牌的数量
首先要对给定牌组中每种牌的出现次数进行统计,这是后续判断能否组成 “葫芦” 以及寻找符合条件 “葫芦” 的基础。通过创建一个长度为14的数组count(因为牌面值范围是1到13,多开辟一位方便对应索引操作)来实现统计。遍历输入的牌组数组array,每出现一张牌面值为card的牌,就将count[card]的值加1,如此一来,count数组中每个索引对应的元素值就代表了相应牌面值的牌在牌组中出现的次数。 -
确定牌面值遍历顺序
由于牌面值有特定的大小顺序(A>K>Q>J>10>9>...>2),并非自然的数字顺序,为了按照牌面大小规则去寻找合适的 “葫芦” 组合,定义了一个自定义的遍历顺序数组order,按照1, 13, 12, 11,..., 2的顺序排列。这样后续在遍历牌面值尝试组成 “葫芦” 时,能从大到小(按照牌面大小的实际规则)去考虑各种可能的组合,符合我们要找最大 “葫芦” 组合的要求。 -
寻找符合条件的 “葫芦” 组合
采用两层嵌套循环来寻找符合条件的 “葫芦” 组合:- 外层循环按照自定义的
order顺序遍历牌面值,尝试寻找可以作为三张相同牌面(即牌a)的牌面值。对于每个牌面值i,先判断其在牌组中的数量是否大于等于3,如果满足这个条件,说明有可能以该牌面值的牌组成 “葫芦” 中的三张相同牌部分,接下来就进入内层循环去寻找合适的另外两张相同牌面(即牌b)。 - 内层循环同样依据
order顺序遍历牌面值,对于每个牌面值j,首先要确保它与外层循环当前的牌面值i不同(因为a和b牌面不同),并且其在牌组中的数量要大于等于2。当找到这样一个牌面值j后,还需要进一步检查由3张牌面值为i的牌和2张牌面值为j的牌组成的 “葫芦”,其牌面值之和是否不超过给定的最大值max,也就是判断3 * i + 2 * j <= max是否成立。如果这个条件也满足,那么就找到了符合所有条件的 “葫芦” 组合,直接返回包含牌a(即i)和牌b(即j)牌面值的数组[i, j]。
- 外层循环按照自定义的
-
处理未找到符合条件 “葫芦” 的情况
如果经过两层循环遍历完所有可能的牌面值组合后,都没有找到满足条件的 “葫芦”,那就按照题目要求,返回[0, 0]表示不存在符合规则的 “葫芦” 组合。
三、具体解题步骤
-
牌数量统计步骤
创建了count数组用于统计牌数,然后通过增强for循环遍历输入的牌组数组array,对于数组中的每一张牌card,将count数组中对应索引位置(索引与牌面值对应)的元素值加1,以此完成对每种牌在牌组中出现次数的统计。 -
定义牌面值遍历顺序
定义了 order 数组,明确了后续按照牌面大小规则去遍历牌面值的顺序,使得寻找 “葫芦” 组合时能从牌面大的开始考虑,符合寻找最大 “葫芦” 组合的目标。
- 寻找 “葫芦” 组合的循环操作
外层 for 循环依据 order 数组遍历牌面值,对于每个牌面值 i,先判断其在牌组中的数量是否足够组成 “葫芦” 中的三张相同牌(count[i] >= 3)。若满足条件,则进入内层 for 循环,内层循环同样按照 order 数组遍历其他牌面值 j,首先筛选出与 i 不同且数量满足组成两张相同牌(j!= i && count[j] >= 2)的牌面值。找到这样的 j 后,再通过 3 * i + 2 * j <= max 判断由它们组成的 “葫芦” 牌面值之和是否符合不超过 max 的限制条件,若符合,则找到了符合要求的 “葫芦” 组合,直接返回包含 i 和 j 的数组 [i, j]。
- 未找到 “葫芦” 的返回处理
如果前面的循环遍历完都没有找到符合条件的 “葫芦” 组合,最后就返回 [0, 0],按照题目规定表示不存在满足规则的 “葫芦”。
例如,对于样例 n = 9, max = 34, array = [6, 6, 6, 8, 8, 8, 5, 5, 1]:
- 首先统计牌数,得到
count数组中对应牌面值6的数量为3,牌面值8的数量为3,牌面值5的数量为2等情况。 - 按照
order顺序遍历,先从大的牌面值开始,当遍历到牌面值8时,发现其数量大于等于3,于是进入内层循环找另外两张相同牌面的牌。在内层循环中,当遍历到牌面值5时,它与8不同且数量大于等于2,然后计算3 * 8 + 2 * 5 = 34,刚好不超过给定的最大值34,所以找到了符合条件的 “葫芦” 组合,返回[8, 5]。
public class Main {
public static int[] solution(int n, int max, int[] array) {
// 统计每种牌的数量
int[] count = new int[14]; // 因为牌面值范围是1到13
for (int card : array) {
count[card]++;
}
// 自定义牌面值的遍历顺序:1, 13, 12, 11, ..., 2
int[] order = {1, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2};
// 从自定义顺序中遍历牌面值,寻找三张相同的牌
for (int i : order) {
if (count[i] >= 3) {
// 找到三张相同的牌,接下来寻找两张相同的牌
for (int j : order) {
if (j != i && count[j] >= 2) {
// 检查牌面值之和是否不超过max
if (3 * i + 2 * j <= max) {
return new int[]{i, j};
}
}
}
}
}
// 如果没有找到符合条件的“葫芦”,返回{0, 0}
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是牌组中牌的数量。 - 接着在寻找 “葫芦” 组合的两层嵌套循环中,外层循环遍历
order数组,其长度是固定的13(牌面值种类数),内层循环同样遍历order数组,所以这部分的时间复杂度可以看作是常数时间复杂度与常数相乘,依然是常数级别,不会随着输入牌组规模变化而变化。 - 综合来看,整体时间复杂度主要由统计牌数量的操作决定,即为 。
- 首先统计牌的数量时,需要遍历一次输入的牌组数组
-
空间复杂度
代码中创建了count数组用于统计牌数,其长度固定为14,与输入牌组的数量n无关,另外定义了order数组,长度也是固定的13。除此之外,没有随着输入规模增长而大量占用额外空间的数据结构使用,所以空间复杂度为 (不考虑输入的牌组数组本身占用的空间)。