华为OD机试真题——斗地主之顺子(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型

本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式;
并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析;
本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分享

华为OD机试真题《斗地主之顺子》:


文章快捷目录

题目描述及说明

Java

python

JavaScript

C

GO

更多内容


题目名称:斗地主之顺子


  1. 知识点:字符串处理、排序算法、逻辑判断
  2. 时间限制:1秒
  3. 空间限制:256MB
  4. 限定语言:不限

题目描述

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

  1. 由至少5张连续递增的牌组成(例如:{3,4,5,6,7}或{3,4,5,...,K,A})。
  2. 不能包含2(如{J,Q,K,A,2}无效)。
  3. 不允许非连续或重复牌(如{3,4,5,6,8}无效)。

输入

13张合法扑克牌(空格隔开,不含大小王),例如:2 9 J 2 3 4 K A 7 9 A 5 6

输出

  • 若有顺子,按首个牌大小升序逐行输出(如3 4 5 6 7)。
  • 多个顺子时分行输出(如示例2)。
  • 无顺子则输出No

示例

  • 输入:2 9 J 2 3 4 K A 7 9 A 5 6 → 输出:3 4 5 6 7
  • 输入:2 9 J 10 3 4 K A 7 Q A 5 6 → 输出:3 4 5 6 79 10 J Q K A

Java

问题分析

我们需要在斗地主游戏中找出所有可能的顺子牌型。顺子由至少5张连续递增的牌组成,不能包含2,且牌不可重复。输入为13张牌,需输出所有可能的顺子,按首个牌的大小升序排列。


解题思路

  1. 数据预处理

    • 将牌面转换为数值,过滤掉2。
    • 去重并排序,得到有序的数值列表。
  2. 寻找连续序列

    • 遍历排序后的数值列表,找出所有长度≥5的连续递增序列。
  3. 结果转换与输出

    • 将数值序列转换回牌面,按起始牌升序输出。

代码实现

java 复制代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String[] cards = scanner.nextLine().split(" ");
        
        // 建立牌面到数值的映射(3→0,A→11,2→12但会被过滤)
        Map<String, Integer> cardToValue = new HashMap<>();
        String[] order = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"};
        for (int i = 0; i < order.length; i++) {
            cardToValue.put(order[i], i);
        }
        
        // 过滤掉2,并转换为不重复的数值集合
        Set<Integer> valueSet = new TreeSet<>();
        for (String card : cards) {
            if (cardToValue.containsKey(card)) { // 忽略2
                valueSet.add(cardToValue.get(card));
            }
        }
        
        List<Integer> sortedValues = new ArrayList<>(valueSet);
        if (sortedValues.size() < 5) { // 无足够牌形成顺子
            System.out.println("No");
            return;
        }
        
        List<List<Integer>> sequences = new ArrayList<>();
        int start = 0; // 当前连续序列的起始索引
        
        // 遍历数值列表,寻找连续序列
        for (int i = 1; i <= sortedValues.size(); i++) {
            if (i < sortedValues.size() && sortedValues.get(i) == sortedValues.get(i-1) + 1) {
                continue; // 继续连续序列
            } else {
                int length = i - start;
                if (length >= 5) {
                    List<Integer> sub = sortedValues.subList(start, i); // 截取连续序列
                    sequences.add(new ArrayList<>(sub)); // 避免引用问题
                }
                start = i; // 重置起始索引
            }
        }
        
        // 转换为牌面并输出
        List<List<String>> result = new ArrayList<>();
        for (List<Integer> seq : sequences) {
            List<String> sequence = new ArrayList<>();
            for (int val : seq) {
                sequence.add(order[val]);
            }
            result.add(sequence);
        }
        
        if (result.isEmpty()) {
            System.out.println("No");
        } else {
            for (List<String> seq : result) {
                System.out.println(String.join(" ", seq));
            }
        }
    }
}

代码详细解析

  1. 输入处理

    • 使用Scanner读取输入并分割为牌面数组。
  2. 牌面到数值的映射

    • 使用数组order定义牌面顺序,建立cardToValue映射。
  3. 过滤与去重

    • 遍历输入的牌,过滤掉2,并将牌面转换为数值存入TreeSet(自动排序并去重)。
  4. 寻找连续序列

    • 遍历排序后的数值列表,通过比较相邻数值判断是否连续。
    • 发现不连续时,若当前序列长度≥5,则记录该序列。
  5. 结果转换与输出

    • 将数值序列转换为对应的牌面,按顺序输出。

示例测试

示例1

输入:2 9 J 2 3 4 K A 7 9 A 5 6

输出:

复制代码
3 4 5 6 7

解析:数值序列0,1,2,3,4对应牌面3-7。

示例2

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

输出:

复制代码
3 4 5 6 7  
9 10 J Q K A

解析:两个连续序列0-4(3-7)和6-11(9-A)。

示例3

输入:2 2 2 2 2 2 2 2 2 2 2 2 2

输出:
No

解析:所有牌都是2,无法组成顺子。


综合分析

  1. 时间复杂度

    • 预处理:O(n),其中n为输入牌数。
    • 寻找连续序列:O(m),m为去重后的牌数。
  2. 空间复杂度

    • 使用TreeSet和列表存储数值,空间复杂度为O(m)。
  3. 正确性

    • 通过去重和排序确保每个顺子唯一且连续,遍历过程准确捕捉所有可能序列。
  4. 适用性

    • 处理任意合法输入,包括重复牌和复杂分布,确保结果正确。

python

问题分析

我们需要在斗地主游戏中找出所有可能的顺子牌型。顺子由至少5张连续递增的牌组成,不能包含2,且牌不可重复。输入为13张牌,需输出所有可能的顺子,按首个牌的大小升序排列。


解题思路

  1. 数据预处理

    • 将牌面转换为数值,过滤掉2。
    • 去重并排序,得到有序的数值列表。
  2. 寻找连续序列

    • 遍历排序后的数值列表,找出所有长度≥5的连续递增序列。
  3. 结果转换与输出

    • 将数值序列转换回牌面,按起始牌升序输出。

代码实现

python 复制代码
def main():
    # 读取输入并分割成牌列表
    input_cards = input().split()
    
    # 定义牌面顺序映射:3->0, 4->1,..., A->11,2被过滤
    card_order = ["3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]
    card_value = {card: idx for idx, card in enumerate(card_order)}
    
    # 过滤2并将牌转换为数值,去重后排序
    values = []
    seen = set()
    for card in input_cards:
        if card in card_value:  # 过滤掉2
            val = card_value[card]
            if val not in seen:
                seen.add(val)
                values.append(val)
    values.sort()
    
    if len(values) < 5:
        print("No")
        return
    
    # 寻找所有连续序列
    sequences = []
    start = 0
    for i in range(1, len(values) + 1):
        if i < len(values) and values[i] == values[i-1] + 1:
            continue
        else:
            if i - start >= 5:
                sequences.append(values[start:i])
            start = i
    
    if not sequences:
        print("No")
        return
    
    # 按序列起始值排序
    sequences.sort(key=lambda x: x[0])
    
    # 转换回牌面并输出
    for seq in sequences:
        converted = [card_order[val] for val in seq]
        print(" ".join(converted))

if __name__ == "__main__":
    main()

代码详细解析

  1. 输入处理

    • input().split()读取输入并分割为牌列表。
  2. 牌面映射

    • card_order列表定义牌面顺序,card_value字典将牌面映射到数值(3→0,A→11)。
  3. 过滤与去重

    • 遍历输入的牌,过滤掉2,转换为数值存入values列表,同时用集合seen去重。
    • values排序,得到升序排列的数值列表。
  4. 寻找连续序列

    • 初始化start记录当前连续序列的起始索引。
    • 遍历数值列表,当发现不连续时,检查当前序列长度是否≥5,若是则记录。
    • 示例:输入[0,1,2,3,4,6,7,8,9,10,11],找到0-46-11两个序列。
  5. 结果处理

    • 若无有效序列,输出"No"。
    • 按每个序列的起始值排序,确保输出顺序正确。
    • 将数值序列转换回牌面字符串,用空格连接后逐行输出。

示例测试

示例1

输入:2 9 J 2 3 4 K A 7 9 A 5 6

输出:

复制代码
3 4 5 6 7

解析:数值序列[0,1,2,3,4]对应3-7。

示例2

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

输出:

复制代码
3 4 5 6 7  
9 10 J Q K A

解析:数值序列[0,1,2,3,4][6,7,8,9,10,11],分别对应3-7和9-A。

示例3

输入:2 2 2 2 2 2 2 2 2 2 2 2 2

输出:
No

解析:所有牌都是2,无法形成顺子。


综合分析

  1. 时间复杂度

    • 排序:O(n log n),n为去重后的牌数(最多12种)。
    • 遍历找序列:O(n),线性扫描。
    • 整体复杂度为O(n log n),高效处理题目限制。
  2. 空间复杂度

    • 存储数值列表和序列列表,空间复杂度O(n),满足题目要求。
  3. 正确性

    • 去重和排序确保每个顺子唯一且连续,严格遵循顺子规则。
    • 边界情况处理完善(如全为2或无足够牌)。
  4. 适用性

    • 直接处理输入的字符串,适应各种合法输入组合。
    • 代码简洁高效,逻辑清晰易于扩展。

JavaScript

问题分析

我们需要在斗地主游戏中找出所有可能的顺子牌型。顺子由至少5张连续递增的牌组成,不能包含2,且牌不可重复。输入为13张牌,需输出所有可能的顺子,按首个牌的大小升序排列。


解题思路

  1. 数据预处理

    • 将牌面转换为数值(例如 3→04→1A→11)。
    • 过滤掉所有 2,并去重后按数值排序。
  2. 寻找连续序列

    • 遍历排序后的数值列表,找出所有长度≥5的连续递增序列。
  3. 结果转换与输出

    • 将数值序列转换回牌面,按起始牌升序输出。

代码实现

javascript 复制代码
const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

rl.on('line', (input) => {
    const cards = input.split(' ');
    
    // 定义牌面到数值的映射(3→0,A→11,2被过滤)
    const cardOrder = ["3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"];
    const cardValue = {};
    cardOrder.forEach((card, idx) => cardValue[card] = idx);
    
    // 1. 过滤掉2,转换为数值并去重
    const seen = new Set();
    const values = [];
    for (const card of cards) {
        if (card in cardValue) { // 过滤掉2
            const val = cardValue[card];
            if (!seen.has(val)) { // 去重
                seen.add(val);
                values.push(val);
            }
        }
    }
    values.sort((a, b) => a - b); // 按数值升序
    
    // 2. 寻找连续序列
    const sequences = [];
    let start = 0;
    for (let i = 1; i <= values.length; i++) {
        // 检查是否连续
        if (i < values.length && values[i] === values[i - 1] + 1) {
            continue;
        } else {
            const length = i - start;
            if (length >= 5) {
                sequences.push(values.slice(start, i));
            }
            start = i; // 重置起始位置
        }
    }
    
    // 3. 转换回牌面并按起始牌升序排序
    const result = sequences
        .map(seq => seq.map(val => cardOrder[val])) // 数值转牌面
        .sort((a, b) => cardValue[a[0]] - cardValue[b[0]]); // 按起始牌排序
    
    // 输出结果
    if (result.length === 0) {
        console.log("No");
    } else {
        result.forEach(seq => console.log(seq.join(' ')));
    }
});

代码详细解析

  1. 输入处理

    • input.split(' ') 将输入字符串按空格分割为牌面数组。
    • 示例输入:2 9 J 2 3 4 K A 7 9 A 5 6 → 分割为 ['2', '9', 'J', ..., '6']
  2. 牌面到数值的映射

    • cardOrder 定义顺序,cardValue 将牌面映射到数值(例如 '3'→0'A'→11)。
  3. 过滤与去重

    • 遍历输入牌面,过滤掉 2,并将牌面转换为数值。
    • 使用 Set 去重,确保数值唯一。
    • 示例过滤后:['9', 'J', '3', '4', ...] → 转换为 [6, 8, 0, 1, ...] → 去重后排序为 [0, 1, 2, 3, 4, 6, 8, 10, 11]
  4. 寻找连续序列

    • 遍历排序后的数值,记录连续递增的起始索引 start
    • 当发现不连续时,检查当前序列长度是否≥5。
    • 示例排序后的数值 [0, 1, 2, 3, 4] → 记录为连续序列。
  5. 结果转换与输出

    • 将数值序列转换回牌面(例如 0→'3')。
    • 按起始牌升序排序(例如 39 前)。
    • 输出结果,若无顺子则输出 No

示例测试

示例1

输入:

复制代码
2 9 J 2 3 4 K A 7 9 A 5 6

输出:

复制代码
3 4 5 6 7

示例2

输入:

复制代码
2 9 J 10 3 4 K A 7 Q A 5 6

输出:

复制代码
3 4 5 6 7
9 10 J Q K A

示例3

输入:

复制代码
2 2 2 2 2 2 2 2 2 2 2 2 2

输出:

复制代码
No

综合分析

  1. 时间复杂度

    • 过滤和去重:O(n),线性遍历输入。
    • 排序:O(m log m),m 为去重后的牌数(最多12)。
    • 寻找连续序列:O(m),线性扫描。
  2. 空间复杂度

    • 存储数值和序列,空间复杂度为 O(m)。
  3. 正确性

    • 严格过滤 2 和重复牌。
    • 正确检测连续递增序列,确保顺子规则。
  4. 适用性

    • 支持所有合法输入,处理复杂情况如多个顺子和边界条件。

C++

问题分析

需求:从13张牌中找出所有满足以下条件的顺子:

  1. 至少5张连续递增的牌(如3,4,5,6,7)。
  2. 不包含2(如J,Q,K,A,2无效)。
  3. 不允许重复或非连续牌(如3,4,5,6,8无效)。

输入 :13张合法扑克牌(如2 9 J 2 3 4 K A 7 9 A 5 6)。
输出 :按首个牌升序输出所有顺子,无顺子则输出No


解题思路
  1. 数据预处理
    • 过滤掉所有2,并将牌面转换为数值(3→0,A→11)。
    • 去重后按数值排序。
  2. 连续序列检测
    • 遍历排序后的数值,找出所有长度≥5的连续区间。
  3. 结果处理
    • 转换回牌面字符串,按起始牌升序输出。

代码实现

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <map>
#include <set>

using namespace std;

// 分割字符串为牌面数组
vector<string> split(const string &s) {
    vector<string> tokens;
    string token;
    istringstream iss(s);
    while (iss >> token) {
        tokens.push_back(token);
    }
    return tokens;
}

int main() {
    // 1. 读取输入并分割为牌面数组
    string input;
    getline(cin, input);
    vector<string> cards = split(input);

    // 2. 牌面到数值的映射(3→0,A→11,2被过滤)
    map<string, int> card_value = {
        {"3", 0}, {"4", 1}, {"5", 2}, {"6", 3},
        {"7", 4}, {"8", 5}, {"9", 6}, {"10", 7},
        {"J", 8}, {"Q", 9}, {"K", 10}, {"A", 11}
    };

    // 3. 过滤2并去重
    set<int> unique_values;
    for (const auto &card : cards) {
        if (card_value.find(card) != card_value.end()) {
            unique_values.insert(card_value[card]);
        }
    }

    // 4. 转换为排序后的数值数组
    vector<int> values(unique_values.begin(), unique_values.end());
    sort(values.begin(), values.end());

    // 5. 检查是否有足够牌数
    if (values.size() < 5) {
        cout << "No" << endl;
        return 0;
    }

    // 6. 寻找连续序列
    vector<vector<int>> sequences;
    int start = 0;
    for (int i = 1; i <= values.size(); ++i) {
        if (i < values.size() && values[i] == values[i - 1] + 1) {
            continue;
        } else {
            int length = i - start;
            if (length >= 5) {
                vector<int> seq(values.begin() + start, values.begin() + i);
                sequences.push_back(seq);
            }
            start = i;
        }
    }

    // 7. 处理结果
    if (sequences.empty()) {
        cout << "No" << endl;
        return 0;
    }

    // 8. 按起始牌升序排序
    sort(sequences.begin(), sequences.end(), [](const vector<int> &a, const vector<int> &b) {
        return a[0] < b[0];
    });

    // 9. 数值转牌面
    const vector<string> card_order = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"};
    vector<vector<string>> result;
    for (const auto &seq : sequences) {
        vector<string> converted;
        for (int val : seq) {
            converted.push_back(card_order[val]);
        }
        result.push_back(converted);
    }

    // 10. 输出结果
    for (const auto &seq : result) {
        for (size_t i = 0; i < seq.size(); ++i) {
            if (i > 0) cout << " ";
            cout << seq[i];
        }
        cout << endl;
    }

    return 0;
}

代码详细解析

  1. 输入处理
    • split(input):将输入字符串分割为牌面数组(如["2", "9", "J", ...])。
  2. 牌面映射
    • card_value:建立牌面到数值的映射(如"3"→0)。
  3. 过滤与去重
    • unique_values:用set过滤掉2并去重。
  4. 排序数值
    • sort(values):将数值升序排列(如[0,1,2,3,4])。
  5. 连续序列检测
    • 遍历数值数组,维护start记录连续区间的起始位置。
    • 当发现不连续时,若当前区间长度≥5,保存序列。
  6. 结果处理
    • 将数值序列转换回牌面,并按起始牌升序排序输出。

示例测试

示例1:输入

复制代码
2 9 J 2 3 4 K A 7 9 A 5 6

输出

复制代码
3 4 5 6 7

示例2:输入

复制代码
2 9 J 10 3 4 K A 7 Q A 5 6

输出

复制代码
3 4 5 6 7
9 10 J Q K A

示例3:输入

复制代码
2 2 2 2 2 2 2 2 2 2 2 2 2

输出

复制代码
No

综合分析

  1. 时间复杂度

    • 过滤去重:O(n),n为输入牌数(13)。
    • 排序:O(m log m),m为去重后的牌数(最多12)。
    • 序列检测:O(m),线性遍历。
    • 总时间复杂度:O(n + m log m),高效处理题目限制。
  2. 空间复杂度

    • 存储数值数组和序列结果,空间复杂度O(m)。
  3. 正确性

    • 严格过滤2和重复牌,确保连续序列的正确性。
  4. 适用性

    • 可处理任意合法输入,包括多个顺子或无顺子的边界情况。

C

问题分析

需求:从13张牌中找出所有满足以下条件的顺子:

  1. 至少5张连续递增的牌(如 3,4,5,6,7)。
  2. 不包含 2(如 J,Q,K,A,2 无效)。
  3. 不允许重复或非连续牌(如 3,4,5,6,8 无效)。

输入 :13张合法扑克牌(如 2 9 J 2 3 4 K A 7 9 A 5 6)。
输出 :按首个牌升序输出所有顺子,无顺子则输出 No


解题思路
  1. 输入处理:分割输入字符串为牌面数组。
  2. 牌面映射 :将牌面(如 3)映射为数值(如 0)。
  3. 过滤与去重 :过滤掉 2,去重后按数值排序。
  4. 连续序列检测:遍历数值数组,找出长度≥5的连续区间。
  5. 结果处理:转换回牌面字符串,按起始牌升序输出。

代码实现

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

// 牌面顺序数组(3→0,A→11)
const char *CARD_ORDER[] = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"};

// 牌面到数值的映射结构体
typedef struct {
    char name[3]; // 牌面字符串(如"10"需要2字符)
    int value;     // 对应的数值
} CardMap;

// 初始化牌面映射表
CardMap card_map[] = {
    {"3", 0}, {"4", 1}, {"5", 2}, {"6", 3},
    {"7", 4}, {"8", 5}, {"9", 6}, {"10",7},
    {"J", 8}, {"Q", 9}, {"K", 10}, {"A", 11}
};

// 判断牌是否有效(非2)
bool is_valid_card(const char *card) {
    for (int i = 0; i < 12; i++) {
        if (strcmp(card, card_map[i].name) == 0) {
            return true;
        }
    }
    return false;
}

// 获取牌对应的数值
int get_card_value(const char *card) {
    for (int i = 0; i < 12; i++) {
        if (strcmp(card, card_map[i].name) == 0) {
            return card_map[i].value;
        }
    }
    return -1; // 无效牌(如2)
}

// 检查数组中是否包含某个值
bool contains(int *arr, int size, int val) {
    for (int i = 0; i < size; i++) {
        if (arr[i] == val) return true;
    }
    return false;
}

// 比较函数用于排序
int compare(const void *a, const void *b) {
    return (*(int *)a - *(int *)b);
}

// 动态数组结构体(用于存储顺子序列)
typedef struct {
    int *data;
    int size;
} IntArray;

// 创建动态数组
IntArray create_int_array() {
    IntArray arr;
    arr.data = NULL;
    arr.size = 0;
    return arr;
}

// 添加元素到动态数组
void append_int_array(IntArray *arr, int value) {
    arr->data = realloc(arr->data, (arr->size + 1) * sizeof(int));
    arr->data[arr->size++] = value;
}

// 释放动态数组内存
void free_int_array(IntArray *arr) {
    free(arr->data);
    arr->size = 0;
}

int main() {
    char input[100];
    fgets(input, sizeof(input), stdin);
    
    // 1. 分割输入字符串为牌面数组
    char *token = strtok(input, " \n");
    char *cards[13];
    int card_count = 0;
    while (token != NULL && card_count < 13) {
        cards[card_count] = malloc(strlen(token) + 1);
        strcpy(cards[card_count], token);
        card_count++;
        token = strtok(NULL, " \n");
    }
    
    // 2. 过滤2并收集去重的数值
    int values[13];
    int value_count = 0;
    for (int i = 0; i < card_count; i++) {
        if (is_valid_card(cards[i])) {
            int val = get_card_value(cards[i]);
            if (!contains(values, value_count, val)) {
                values[value_count++] = val;
            }
        }
        free(cards[i]); // 释放临时内存
    }
    
    // 3. 排序数值数组
    qsort(values, value_count, sizeof(int), compare);
    
    // 4. 寻找连续序列
    IntArray sequences[13]; // 存储所有顺子序列
    int seq_count = 0;
    int start = 0;
    for (int i = 1; i <= value_count; i++) {
        if (i < value_count && values[i] == values[i-1] + 1) {
            continue;
        } else {
            int length = i - start;
            if (length >= 5) {
                sequences[seq_count] = create_int_array();
                for (int j = start; j < i; j++) {
                    append_int_array(&sequences[seq_count], values[j]);
                }
                seq_count++;
            }
            start = i;
        }
    }
    
    // 5. 按起始牌升序排序序列
    for (int i = 0; i < seq_count; i++) {
        for (int j = i+1; j < seq_count; j++) {
            if (sequences[i].data[0] > sequences[j].data[0]) {
                IntArray temp = sequences[i];
                sequences[i] = sequences[j];
                sequences[j] = temp;
            }
        }
    }
    
    // 6. 输出结果
    if (seq_count == 0) {
        printf("No\n");
    } else {
        for (int i = 0; i < seq_count; i++) {
            for (int j = 0; j < sequences[i].size; j++) {
                printf("%s", CARD_ORDER[sequences[i].data[j]]);
                if (j != sequences[i].size - 1) printf(" ");
            }
            printf("\n");
            free_int_array(&sequences[i]); // 释放内存
        }
    }
    
    return 0;
}

代码详细解析

  1. 输入处理

    • fgets 读取输入行,strtok 分割字符串为牌面数组。
    • 示例输入:2 9 J 2 3 4 K A 7 9 A 5 6 → 分割为 ["2", "9", "J", ...]
  2. 过滤与去重

    • is_valid_card 判断牌是否为非 2
    • get_card_value 将牌面转换为数值(如 "3"→0)。
    • contains 检查是否已存在重复值。
  3. 排序数值

    • qsort 对数值数组升序排序。
  4. 连续序列检测

    • 维护 start 记录连续区间的起始位置。
    • 当发现不连续时,若长度≥5,保存序列到动态数组。
  5. 结果排序

    • 冒泡排序按顺子的起始牌升序排列。
  6. 输出处理

    • 将数值转换为牌面字符串(如 0→"3"),按格式输出。

示例测试

示例1:输入

复制代码
2 9 J 2 3 4 K A 7 9 A 5 6

输出

复制代码
3 4 5 6 7

示例2:输入

复制代码
2 9 J 10 3 4 K A 7 Q A 5 6

输出

复制代码
3 4 5 6 7
9 10 J Q K A

示例3:输入

复制代码
2 2 2 2 2 2 2 2 2 2 2 2 2

输出

复制代码
No

综合分析

  1. 时间复杂度

    • 过滤去重 :O(n²),contains 需要线性查找。
    • 排序:O(n log n),使用快速排序。
    • 序列检测:O(n),线性遍历。
    • 总时间复杂度:O(n² + n log n),适用于小规模输入(n ≤13)。
  2. 空间复杂度

    • 数值数组和动态序列数组,空间复杂度为 O(n²)。
  3. 正确性

    • 严格过滤 2 和重复牌,正确检测连续序列。
  4. 适用性

    • 处理输入边界情况(如全为 2 或重复牌)。
    • 动态内存管理确保资源有效利用。

GO

问题分析

需求:从13张牌中找出所有满足以下条件的顺子:

  1. 至少5张连续递增的牌(如 3,4,5,6,7)。
  2. 不包含 2(如 J,Q,K,A,2 无效)。
  3. 不允许重复或非连续牌(如 3,4,5,6,8 无效)。

输入 :13张合法扑克牌(如 2 9 J 2 3 4 K A 7 9 A 5 6)。
输出 :按首个牌升序输出所有顺子,无顺子则输出 No


解题思路
  1. 输入处理:读取输入字符串并分割为牌面数组。
  2. 牌面映射 :将牌面转换为数值(3→0A→11),过滤 2 并去重。
  3. 排序数值:按数值升序排列。
  4. 连续序列检测:遍历排序后的数值,找出所有长度≥5的连续区间。
  5. 结果处理:转换回牌面字符串,按起始牌升序输出。

代码实现

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strings"
)

func main() {
	// 定义牌面顺序和映射
	cardOrder := []string{"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}
	cardValue := make(map[string]int)
	for i, card := range cardOrder {
		cardValue[card] = i
	}

	// 读取输入
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Scan()
	input := scanner.Text()

	// 分割输入并过滤2
	cards := strings.Fields(input)
	uniqueValues := make(map[int]bool)
	values := make([]int, 0)

	for _, card := range cards {
		if val, exists := cardValue[card]; exists {
			if !uniqueValues[val] {
				uniqueValues[val] = true
				values = append(values, val)
			}
		}
	}

	// 检查是否有足够牌数
	if len(values) < 5 {
		fmt.Println("No")
		return
	}

	// 排序数值
	sort.Ints(values)

	// 寻找连续序列
	sequences := make([][]int, 0)
	start := 0

	for i := 1; i <= len(values); i++ {
		if i < len(values) && values[i] == values[i-1]+1 {
			continue
		} else {
			if i-start >= 5 {
				seq := make([]int, i-start)
				copy(seq, values[start:i])
				sequences = append(sequences, seq)
			}
			start = i
		}
	}

	// 处理结果
	if len(sequences) == 0 {
		fmt.Println("No")
		return
	}

	// 按起始牌排序
	sort.Slice(sequences, func(i, j int) bool {
		return sequences[i][0] < sequences[j][0]
	})

	// 转换回牌面并输出
	for _, seq := range sequences {
		converted := make([]string, len(seq))
		for i, val := range seq {
			converted[i] = cardOrder[val]
		}
		fmt.Println(strings.Join(converted, " "))
	}
}

代码详细解析

  1. 牌面映射

    go 复制代码
    cardOrder := []string{"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}
    cardValue := make(map[string]int)
    for i, card := range cardOrder {
        cardValue[card] = i // 3→0, 4→1, ..., A→11
    }
    • 创建牌面到数值的映射表,"3"对应0"A"对应11
  2. 输入处理

    go 复制代码
    scanner := bufio.NewScanner(os.Stdin)
    scanner.Scan()
    input := scanner.Text()
    cards := strings.Fields(input)
    • 读取输入行并分割为牌面数组(如 ["2", "9", "J", ...])。
  3. 过滤与去重

    go 复制代码
    uniqueValues := make(map[int]bool)
    values := make([]int, 0)
    for _, card := range cards {
        if val, exists := cardValue[card]; exists {
            if !uniqueValues[val] {
                uniqueValues[val] = true
                values = append(values, val)
            }
        }
    }
    • 过滤掉 2 并去重,保留唯一数值。
  4. 排序数值

    go 复制代码
    sort.Ints(values)
    • 将数值按升序排列(如 [0,1,2,3,4])。
  5. 连续序列检测

    go 复制代码
    sequences := make([][]int, 0)
    start := 0
    for i := 1; i <= len(values); i++ {
        if i < len(values) && values[i] == values[i-1]+1 {
            continue
        } else {
            if i-start >= 5 {
                seq := make([]int, i-start)
                copy(seq, values[start:i])
                sequences = append(sequences, seq)
            }
            start = i
        }
    }
    • 遍历排序后的数值,记录所有长度≥5的连续区间。
  6. 结果处理

    go 复制代码
    sort.Slice(sequences, func(i, j int) bool {
        return sequences[i][0] < sequences[j][0]
    })
    for _, seq := range sequences {
        converted := make([]string, len(seq))
        for i, val := range seq {
            converted[i] = cardOrder[val]
        }
        fmt.Println(strings.Join(converted, " "))
    }
    • 按起始牌升序排序后,转换回牌面字符串输出。

示例测试

示例1:输入

复制代码
2 9 J 2 3 4 K A 7 9 A 5 6

输出

复制代码
3 4 5 6 7

示例2:输入

复制代码
2 9 J 10 3 4 K A 7 Q A 5 6

输出

复制代码
3 4 5 6 7
9 10 J Q K A

示例3:输入

复制代码
2 2 2 2 2 2 2 2 2 2 2 2 2

输出

复制代码
No

综合分析

  1. 时间复杂度

    • 过滤去重:O(n),线性遍历输入牌面。
    • 排序:O(m log m),m为去重后的牌数(最多12)。
    • 连续序列检测:O(m),线性遍历。
    • 总时间复杂度:O(n + m log m),高效处理题目限制。
  2. 空间复杂度

    • 存储数值数组和序列结果,空间复杂度为O(m)。
  3. 正确性

    • 严格过滤 2 和重复牌,确保连续序列的正确性。
  4. 适用性

    • 处理所有合法输入,包括多个顺子或无顺子的边界情况。
    • 代码简洁高效,逻辑清晰易于维护。

更多内容:

https://www.kdocs.cn/l/cvk0eoGYucWA

本文发表于【纪元A梦】,关注我,获取更多实用教程/资源!

相关推荐
闲人编程14 分钟前
猜数字游戏:从数学原理到交互体验的完整设计指南
python·游戏·交互·内存管理·猜数字·智能辅导·游戏二分查找
blueshaw1 小时前
CMake中的“包管理“模块FetchContent
c++·cmake
牧杉-惊蛰1 小时前
css 数字从0开始增加的动画效果
前端·javascript·css
孤灯淡茶1 小时前
Fiori学习专题十五:Nested Views
前端·javascript·学习
Monly211 小时前
Vue:el-table-tree懒加载数据
前端·javascript·vue.js
肖永威1 小时前
VSCode开发调试Python入门实践(Windows10)
ide·vscode·python
Another Iso1 小时前
同时启动俩个tomcat压缩版
java·tomcat
进取星辰1 小时前
16、路由守卫:设置魔法结界——React 19 React Router
前端·javascript·react.js
LILI000002 小时前
C++静态编译标准库(libgcc、libstdc++)
开发语言·c++
keep intensify2 小时前
【数据结构】- 栈
c语言·数据结构·算法·