青训营X豆包MarsCode 技术训练营第三课 | 豆包MarsCode AI 刷题

56 阅读5分钟

寻找最大葫芦

问题描述

在一场经典的德州扑克游戏中,有一种牌型叫做“葫芦”。“葫芦”由五张牌组成,其中包括三张相同牌面值的牌 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]

要解决这个问题,我们可以采取以下步骤来构建符合要求的“葫芦”组合:

思路

  1. 牌面值映射

    • 根据题目描述,牌的面值排序为:A (1) > K (13) > Q (12) > J (11) > 10 > ... > 2
    • 使用一个字典来映射牌面字符到数字(如 A -> 1, K -> 13, Q -> 12, 等等)。
  2. 统计牌的出现次数

    • 利用 Python 的 collections.Counter 来统计输入牌列表中每个牌面值的出现次数。
  3. 寻找符合条件的葫芦

    • 选择一个牌面值 a,要求该牌面值至少出现 3 次。
    • 选择一个不同的牌面值 b,要求该牌面值至少出现 2 次。
    • 确保 a 和 b 组合的总面值不超过最大值 max,并且优先选择更大的 a 和 b
  4. 优先级

    • 在选定符合条件的葫芦后,我们首先根据 a 比较大小,如果 a 相同,则比较 b

代码实现

pythonCopy Code
from collections import Counter

# 映射牌面值到数字
card_value = {
    'A': 1, 'K': 13, 'Q': 12, 'J': 11, '10': 10, '9': 9, '8': 8, '7': 7, 
    '6': 6, '5': 5, '4': 4, '3': 3, '2': 2
}

def find_best_full_house(n, max_val, array):
    # 将输入牌面转换为对应的数值
    values = [card_value[str(card)] for card in array]
    
    # 统计每个牌面值的数量
    count = Counter(values)
    
    # 找到所有符合“葫芦”条件的牌面值组合
    possible_full_houses = []
    
    # 对每种可能的三张牌组合
    for a in count:
        if count[a] >= 3:  # a 至少有三张
            for b in count:
                if a != b and count[b] >= 2:  # b 至少有两张,且 a != b
                    # 检查总牌面值是否小于等于 max_val
                    if 3 * a + 2 * b <= max_val:
                        possible_full_houses.append((a, b))
    
    # 按照题目要求,优先选最大a,如果a相同则选择最大b
    if possible_full_houses:
        # 排序方式:先按 a 降序,a 相同则按 b 降序
        possible_full_houses.sort(key=lambda x: (x[0], x[1]), reverse=True)
        # 输出最大的葫芦组合
        return [possible_full_houses[0][0], possible_full_houses[0][1]]
    
    # 如果没有符合条件的葫芦,返回 [0, 0]
    return [0, 0]

# 测试样例
print(find_best_full_house(9, 34, [6, 6, 6, 8, 8, 8, 5, 5, 1]))  # 输出:[8, 5]
print(find_best_full_house(9, 37, [9, 9, 9, 9, 6, 6, 6, 6, 13]))  # 输出:[6, 9]
print(find_best_full_house(9, 40, [1, 11, 13, 12, 7, 8, 11, 5, 6]))  # 输出:[0, 0]

解释代码

  1. 卡片值映射:使用字典 card_value 将每个卡片的面值映射为数字。A 映射为 1,K 映射为 13,依此类推。

  2. 计数牌的频率:我们用 collections.Counter 对输入的牌面值进行计数,得到每个牌面值出现的次数。

  3. 筛选“葫芦”组合

    • 遍历所有可能的 a 和 b,如果 a 至少有三张,b 至少有两张且 a != b,则检查它们的总面值是否满足 3 * a + 2 * b <= max_val
    • 如果满足条件,将 (a, b) 组合加入到候选列表中。
  4. 排序和选择最优组合

    • 我们按照 a 的大小降序排序,如果 a 相同,则按 b 的大小降序排序。
    • 如果有符合条件的“葫芦”组合,返回其中最大的组合;否则返回 [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]

时间复杂度分析

  • 计算频率:统计牌面值出现次数的时间复杂度为 O(n),其中 n 是牌的数量。
  • 遍历所有可能的组合:最多需要检查每一对牌面值 (a, b),由于牌面值只有 13 种(从 2 到 A),所以组合的数量为 O(13^2),即常数时间复杂度。
  • 排序操作:在最坏的情况下需要对所有可能的组合进行排序,复杂度为 O(k log k),其中 k 是符合条件的“葫芦”组合数量,最坏情况下 k 是常数。

总体时间复杂度为 O(n + 13^2 log 13),其中 n 是输入的牌数,常数项可以忽略,因此该算法是高效的。