华为OD机试_2025 最长的顺子(Python,100分)(附详细解题思路)

题目描述

斗地主起源于湖北十堰房县,据说是一位叫吴修全的年轻人根据当地流行的扑克玩法“跑得快”改编的,如今已风靡整个中国,并流行于互联网上。

牌型:单顺,又称顺子,最少5张牌,最多12张牌(3…A)不能有2,也不能有大小王,不计花色。

例如: 3-4-5-6-7-8,7-8-9-10-J-Q,3-4-5-6-7-8-9-10-J-Q-K-A

可用的牌 3<4<5<6<7<8<9<10

(共有13×4+2张牌)

输入:

手上有的牌
已经出过的牌(包括对手出的和自己出的牌)
输出:

对手可能构成的最长的顺子(如果有相同长度的顺子,输出牌面最大的那一个),
如果无法构成顺子,则输出 NO-CHAIN。
输入描述
输入的第一行为当前手中的牌

输入的第二行为已经出过的牌

输出描述
最长的顺子

用例

输入 3-3-3-3-4-4-5-5-6-7-8-9-10-J-Q-K-A
4-5-6-7-8-8-8
输出 9-10-J-Q-K-A
说明
输入 3-3-3-3-8-8-8-8
K-K-K-K
输出 NO-CHAIN
说明 剩余的牌无法构成顺子

斗地主游戏:最长顺子分析

一、核心解题思路

问题分析
题目要求找出对手可能构成的最长顺子(相同长度时取牌面最大的),需要处理两种输入:

  1. 当前手中的牌
  2. 已经出过的牌
    需要基于剩余的牌找出最长的连续牌序列(顺子)

关键特性

  1. 牌面顺序:3<4<5<6<7<8<9<10
  2. 牌的数量:每种数字牌(3-A)各有4张
  3. 顺子要求
    • 至少5张连续牌
    • 不能包含2和大小王

解题策略

  1. 计算剩余牌

    • 初始化每种牌的数量为4
    • 减去手中牌和已出牌的数量
    • 标记剩余牌中可用的牌
  2. 寻找最长顺子

    • 扫描牌面顺序(3到A)
    • 找出所有连续的可用牌段
    • 记录最长且牌面最大的连续段
  3. 结果判断

    • 找到长度≥5的顺子则输出
    • 找不到则输出"NO-CHAIN"
二、完整代码实现
def main():
    # 读取输入
    hand_input = input().strip()
    played_input = input().strip()
    
    # 定义牌面顺序
    card_order = ['3','4','5','6','7','8','9','10','J','Q','K','A']
    total_cards = {card:4 for card in card_order}
    
    # 统计手中的牌
    hand_cards = hand_input.split('-') if hand_input else []
    hand_count = {}
    for card in hand_cards:
        hand_count[card] = hand_count.get(card, 0) + 1
    
    # 统计已出牌
    played_cards = played_input.split('-') if played_input else []
    played_count = {}
    for card in played_cards:
        played_count[card] = played_count.get(card, 0) + 1
    
    # 计算剩余牌
    available = []
    for card in card_order:
        hand_num = hand_count.get(card, 0)
        played_num = played_count.get(card, 0)
        remaining = total_cards[card] - hand_num - played_num
        available.append(remaining > 0)  # 标记是否可用
    
    # 寻找最长顺子
    max_length = 0
    best_start_index = -1
    current_start = -1
    current_length = 0
    
    # 遍历牌面顺序寻找连续段
    for i in range(len(available)):
        if available[i]:
            if current_start == -1:
                current_start = i
                current_length = 1
            else:
                current_length += 1
        else:
            if current_start != -1:
                # 更新最长连续段
                if current_length > max_length or (
                    current_length == max_length and current_start > best_start_index
                ):
                    max_length = current_length
                    best_start_index = current_start
                current_start = -1
                current_length = 0
    
    # 检查最后一段连续牌
    if current_start != -1:
        if current_length > max_length or (
            current_length == max_length and current_start > best_start_index
        ):
            max_length = current_length
            best_start_index = current_start
    
    # 输出结果
    if max_length >= 5:
        result = []
        for i in range(best_start_index, best_start_index + max_length):
            result.append(card_order[i])
        print('-'.join(result))
    else:
        print("NO-CHAIN")

if __name__ == "__main__":
    main()
三、示例解析

示例1:输入

3-3-3-3-4-4-5-5-6-7-8-9-10-J-Q-K-A
4-5-6-7-8-8-8

执行过程

  1. 剩余牌计算

    • 3: 4-4=0(不可用)
    • 4: 4-2-1=1(可用)
    • 5: 4-2-1=1(可用)
    • 6: 4-1-1=2(可用)
    • 7: 4-1-1=2(可用)
    • 8: 4-1-3=0(不可用)
    • 9-A: 各4-1=3(可用)
  2. 可用牌标记

    [3,4,5,6,7,8,9,10,J,Q,K,A] → 
    [False, True, True, True, True, False, True, True, True, True, True, True]
    
  3. 连续段检测

    • 第一段:4,5,6,7 → 长度4
    • 第二段:9,10,J,Q,K,A → 长度6(最长)
  4. 输出:9-10-J-Q-K-A

示例2:输入

3-3-3-3-8-8-8-8
K-K-K-K

执行过程

  1. 剩余牌计算

    • 3: 4-4=0
    • 4-7: 各4-0=4(可用)
    • 8: 4-4=0
    • 9-Q: 各4-0=4(可用)
    • K: 4-4=0
    • A: 4-0=4(可用)
  2. 可用牌标记

    [3,4,5,6,7,8,9,10,J,Q,K,A] →
    [False, True, True, True, True, False, True, True, True, True, False, True]
    
  3. 连续段检测

    • 4-7: 长度4
    • 9-Q: 长度4
    • A: 长度1
    • 无长度≥5的段
  4. 输出:NO-CHAIN

四、总结

算法特点

  1. 高效准确:线性扫描算法,时间复杂度O(1)
  2. 逻辑清晰:分阶段处理(统计→计算→扫描)
  3. 边界处理完善:正确处理空输入和边界情况

关键要点

  • 牌面顺序处理:明确定义3到A的顺序
  • 剩余牌计算:总牌数减去手中和已出牌
  • 连续段检测:扫描可用牌标记数组
  • 结果选择
    • 优先选择最长连续段
    • 长度相同时选择起点最大的(牌面最大)

常见错误避免

  1. 忽略牌面顺序要求(3到A连续)
  2. 忘记每种牌有4张的限制
  3. 未处理长度相同时的牌面大小比较
  4. 未检查顺子最小长度(≥5张)

此解法严格按照题目要求实现,通过分步骤处理输入数据、计算剩余牌、扫描连续段,高效解决了最长顺子查找问题。

你可能感兴趣的:(华为OD机试Python版,华为od,python,算法)