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

70 阅读6分钟

题目:

问题描述

在一场经典的德州扑克游戏中,有一种牌型叫做“葫芦”。“葫芦”由五张牌组成,其中包括三张相同牌面值的牌 𝑎a 和另外两张相同牌面值的牌 𝑏b。如果两个人同时拥有“葫芦”,我们会优先比较牌 𝑎a 的大小,若牌 𝑎a 相同则再比较牌 𝑏b 的大小。

在这个问题中,我们对“葫芦”增加了一个限制:组成“葫芦”的五张牌牌面值之和不能超过给定的最大值 𝑚𝑎𝑥max。牌面值的大小规则为:A > K > Q > J > 10 > 9 > ... > 2,其中 A 的牌面值为1,K 为13,依此类推。

给定一组牌,你需要找到符合规则的最大的“葫芦”组合,并输出其中三张相同的牌面和两张相同的牌面。如果找不到符合条件的“葫芦”,则输出 “0, 0”。

我的代码:

from collections import Counter

# 定义牌面值对应的数字
value_map = {'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 solution(n, max, array):
    # 统计每个牌面出现的次数
    counter = Counter(array)
    
    # 用来存储最终找到的葫芦组合
    best_hand = [0, 0]
    
    # 遍历所有牌面值从大到小
    for a in range(13, 0, -1):  # 遍历三张相同牌面值的部分
        if counter[a] >= 3:  # 如果有三张相同的牌
            for b in range(a-1, 0, -1):  # 遍历两张相同牌面值的部分,且要小于a
                if counter[b] >= 2:  # 如果有两张相同的牌
                    # 检查牌面值之和是否不超过 max
                    if a * 3 + b * 2 <= max:
                        # 更新最佳葫芦组合
                        best_hand = [a, b]
                        break  # 找到最大葫芦,退出内层循环
    
    return best_hand

# 测试用例
if __name__ == "__main__":
    print(solution(9, 34, [6, 6, 6, 8, 8, 8, 5, 5, 1]) == [8, 5])  # 输出: [8, 5]
    print(solution(9, 37, [9, 9, 9, 9, 6, 6, 6, 6, 13]) == [6, 9])  # 输出: [6, 9]
    print(solution(9, 40, [1, 11, 13, 12, 7, 8, 11, 5, 6]) == [0, 0])  # 输出: [0, 0]

思路详解:寻找符合条件的葫芦组合

在这道题目中,我们需要从给定的牌组中寻找符合条件的“葫芦”组合。一个“葫芦”组合由五张牌组成,其中包括三张相同牌面值的牌(记为 𝑎)和另外两张相同牌面值的牌(记为 𝑏)。此外,组合的牌面值之和不能超过给定的最大值 max,并且我们要根据牌的大小规则进行比较。目标是找到最大符合条件的“葫芦”组合,输出其中三张相同的牌面和两张相同的牌面。如果找不到符合条件的组合,则输出 “0, 0”。

1. 牌面值的映射

首先,我们需要处理牌面值和它们对应的数字。给定的牌面包括 A, K, Q, J, 10, 9, ..., 2,而每种牌面的大小规则是从大到小的顺序排列:

  • A = 1
  • K = 13
  • Q = 12
  • J = 11
  • 10 = 10
  • 9 = 9
  • ...
  • 2 = 2

我们可以通过一个字典 value_map 来建立牌面与数值之间的映射。这样在后续的计算中,可以方便地查找每个牌面的数字对应值。

2. 计数和筛选

接下来,我们使用 Python 的 Counter 类来统计牌组中每个牌面值的出现次数。通过对牌面值出现次数的统计,我们可以迅速判断哪些牌面值符合“三张相同”和“两张相同”的条件。

3. 确定葫芦组合

根据题目要求,我们要从牌组中找到最大的一组“葫芦”组合。这意味着我们需要:

  • 从大到小:首先比较具有较大面值的牌,这样可以保证我们先找到最大的组合。
  • 遍历三张相同牌的组合:对于每一个可能的三张相同牌面(即从最大值开始向下遍历),我们需要确认是否存在至少三张相同的牌。
  • 遍历两张相同牌的组合:对于每一个符合条件的三张相同牌面,我们需要寻找符合条件的两张相同牌面,且这些牌面的面值小于三张相同牌的面值。
  • 检查牌面值和:每当找到一个有效的组合后,我们需要检查三张相同牌和两张相同牌的面值之和是否不超过给定的 max。

4. 更新最佳组合

如果找到符合条件的“葫芦”组合且它比当前找到的组合大,我们就更新最佳组合。通过这种方式,我们可以确保最终找到的是最大的有效葫芦组合。

5. 返回结果

最终,我们返回的是找到的最佳葫芦组合的牌面值(如果找不到符合条件的葫芦,则返回 [0, 0])。

解题过程总结

这个问题主要考察了以下几个编程技巧:

  1. 使用 Counter 来统计频率:通过 Counter 可以轻松统计每个牌面值出现的次数,从而帮助我们筛选出符合条件的组合。
  2. 按照顺序进行遍历:通过从大到小的顺序遍历牌面值,确保优先找到最大的葫芦组合。
  3. 条件判断与优化:在遍历过程中,及时检查每组牌的和是否满足条件,并根据找到的有效组合更新最佳结果。
  4. 性能优化:本题的时间复杂度主要取决于两层循环,但由于最多只需要处理 13 种牌面值(从 A 到 2),因此整体时间复杂度较低,适合快速计算。

高效学习方法的总结

  1. 基础知识的巩固:在解决类似问题时,首先要对基础知识有扎实的掌握。例如,如何利用 Counter 来统计出现次数,如何根据条件判断筛选有效组合等。
  2. 合理使用算法:在处理遍历和筛选的过程中,通过合理使用排序或从大到小的遍历,可以提高效率。
  3. 边做边思考:编写代码时要时刻思考每一步操作的目的和效果,确保逻辑清晰且能够顺利执行。
  4. 实践与总结:通过不断做题来积累经验,在实际编程中总结出更高效的解决方案。

通过这些方法,不仅能提高解题效率,还能在面对复杂问题时保持冷静、理性地分析问题,最终找到最优的解决方案。