斗地主之顺子

题目描述

在斗地主扑克牌游戏中, 扑克牌由小到大的顺序为: 3,4,5,6,7,8,9,10,J,Q,K,A,2, 玩家可以出的扑克牌阵型有: 单张, 对子, 顺子, 飞机, 炸弹等.

其中顺子的出牌规则为: 由至少5张由小到大连续递增的扑克牌组成, 且不能包含2.

例如: 3,4,5,6,7, 3,4,5,6,7,8,9,10,J,Q,K,A 都是有效的顺子; 而 J,Q,K,A,2, 2,3,4,5,6, 3,4,5,6, 3,4,5,6,8 等都不是顺子.

给定一个包含13张牌的数组, 如果有满足出牌规则的顺子, 请输出顺子.

如果存在多个顺子, 请每行输出一个顺子, 且需要按顺子的第一张牌的大小 (必须从小到大) 依次输出.

如果没有满足出牌规则的顺子, 请输出 No.

输入描述

13张任意顺序的扑克牌, 每张扑克牌数字用空格隔开, 每张扑克牌的数字都是合法的, 并且不包括大小王:

2 9 J 2 3 4 K A 7 9 A 5 6

不需要考虑输入为异常字符的情况

输出描述

组成的顺子, 每张扑克牌数字用空格隔开:

3 4 5 6 7

示例1

输入:

2 9 J 2 3 4 K A 7 9 A 5 6

输出:

3 4 5 6 7

说明: 13张牌中可以组成的顺子只有1组: 3 4 5 6 7.

示例2

输入:

2 9 J 10 3 4 K A 7 Q A 5 6

输出:

2
3 4 5 6 7
9 10 J Q K A

示例3

输入:

2 9 9 9 3 4 K A 10 Q A 5 6

输出:

No

题解

Python

import sys

def num_to_card(num: int) -> str:
    mapping = [
        # 忽略无效的值
        "", "", "",
        # 从3到 A, 2
        "3", "4", "5", "6", "7", "8", "9", "10",
        "J", "Q", "K", "A", "2"
    ]
    return mapping[num]

def card_to_num(card: str) -> int:
    mapping = {
        "3": 3,
        "4": 4,
        "5": 5,
        "6": 6,
        "7": 7,
        "8": 8,
        "9": 9,
        "10": 10,
        "J": 11,
        "Q": 12,
        "K": 13,
        "A": 14,
        "2": 15,
    }
    return mapping[card]

def main():
    # 读取所有的牌
    cards = [card_to_num(card) for card in input().split()]
    cards.sort()
    assert len(cards) == 13

    flash_list = []
    last_flash_card = 15

    first_card = 3
    while first_card < 10:
        if first_card not in cards:
            first_card += 1
            continue

        temp_cards = []
        for card in range(first_card, last_flash_card):
            if card in cards:
                temp_cards.append(card)
            elif len(temp_cards) >= 5:
                # 保存顺子
                for card in temp_cards:
                    cards.remove(card)
                flash_list.append(temp_cards)
                temp_cards = []
            else:
                for card in temp_cards:
                    cards.remove(card)
                temp_cards = []

        # 检查最后一组顺子
        if len(temp_cards) >= 5:
            # 保存顺子
            for card in temp_cards:
                cards.remove(card)
            flash_list.append(temp_cards)
            temp_cards = []

    # 给顺子排序
    # 1. 基于顺子中的第一张牌
    # 2. 基于顺子的长度
    flash_list.sort(key = lambda flash: (flash[0], len(flash)))

    # 打印结果
    # 将数字转换成牌
    if flash_list:
        print(len(flash_list))
        for flash in flash_list:
            print(" ".join(num_to_card(num) for num in flash))
    else:
        print("No")

if __name__ == "__main__":
    main()

Rust

use std::io::{stdin, BufRead};
use std::mem;

fn num_to_card(num: i32) -> &'static str {
    match num {
        // 从3到 A, 2
        // 忽略无效的值
        3 => "3",
        4 => "4",
        5 => "5",
        6 => "6",
        7 => "7",
        8 => "8",
        9 => "9",
        10 => "10",
        11 => "J",
        12 => "Q",
        13 => "K",
        14 => "A",
        15 => "2",
        _ => panic!("Invalid card num"),
    }
}

// 将牌转换成整数
fn card_to_num(card: &str) -> i32 {
    match card {
        "3" => 3,
        "4" => 4,
        "5" => 5,
        "6" => 6,
        "7" => 7,
        "8" => 8,
        "9" => 9,
        "10" => 10,
        "J" => 11,
        "Q" => 12,
        "K" => 13,
        "A" => 14,
        "2" => 15,
        _ => panic!("Invalid card"),
    }
}

fn remove_slice<T: PartialEq>(list1: &mut Vec<T>, list2: &[T]) -> usize {
    let mut count = 0;
    for item in list2 {
        if let Some(pos) = list1.iter().position(|x| x == item) {
            list1.remove(pos);
            count += 1;
        }
    }
    count
}

fn main() {
    // 读取所有的牌
    let mut line = String::new();
    let ret = stdin().lock().read_line(&mut line);
    assert!(ret.is_ok());
    let mut cards: Vec<i32> = line.split_ascii_whitespace().map(card_to_num).collect();
    cards.sort_unstable();
    assert_eq!(cards.len(), 13);

    let mut flash_list = Vec::new();
    let last_flash_card = 15;
    let mut first_card = 3;
    // 找出所有的顺子
    while first_card < 10 {
        // 顺子中的第一张牌.
        if !cards.contains(&first_card) {
            first_card += 1;
            continue;
        }

        let mut temp_cards = Vec::new();
        for card in first_card..last_flash_card {
            if cards.contains(&card) {
                temp_cards.push(card);
            } else if temp_cards.len() >= 5 {
                // 有效顺子, 保存顺子
                remove_slice(&mut cards, &temp_cards);
                let mut flash = Vec::new();
                mem::swap(&mut flash, &mut temp_cards);
                flash_list.push(flash);
            } else {
                // 无效顺子
                remove_slice(&mut cards, &temp_cards);
                temp_cards.clear();
            }
        }

        // 检查最后一组顺子
        if temp_cards.len() >= 5 {
            // 保存顺子
            remove_slice(&mut cards, &temp_cards);
            flash_list.push(temp_cards);
        }
    }

    // 给顺子排序
    // 1. 基于顺子中的第一张牌
    // 2. 基于顺子的长度
    flash_list.sort_by_key(|flash| (flash[0], flash.len()));

    // 打印结果
    // 将数字转换成牌
    if !flash_list.is_empty() {
        println!("{}", flash_list.len());
        for flash in flash_list {
            let s = flash
                .into_iter()
                .map(num_to_card)
                .collect::<Vec<_>>()
                .join(" ");
            println!("{s}");
        }
    } else {
        println!("No");
    }
}