当前位置: 首页 > news >正文

华为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. 结果转换与输出

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

代码实现

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)) { // 忽略2valueSet.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. 结果转换与输出

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

代码实现

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:  # 过滤掉2val = 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 = 0for i in range(1, len(values) + 1):if i < len(values) and values[i] == values[i-1] + 1:continueelse:if i - start >= 5:sequences.append(values[start:i])start = iif 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. 结果转换与输出

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

代码实现

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) { // 过滤掉2const 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. 结果处理
    • 转换回牌面字符串,按起始牌升序输出。

代码实现

#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. 结果处理:转换回牌面字符串,按起始牌升序输出。

代码实现

#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. 结果处理:转换回牌面字符串,按起始牌升序输出。

代码实现

package mainimport ("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()// 分割输入并过滤2cards := 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] = truevalues = append(values, val)}}}// 检查是否有足够牌数if len(values) < 5 {fmt.Println("No")return}// 排序数值sort.Ints(values)// 寻找连续序列sequences := make([][]int, 0)start := 0for 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. 牌面映射

    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. 输入处理

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

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

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

    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. 结果处理

    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梦】,关注我,获取更多实用教程/资源!

相关文章:

  • JDK-17 保姆级安装教程(附安装包)
  • 运维工作中,Ansible常用模块有哪些?
  • 【Python-Day 8】从入门到精通:Python 条件判断 if-elif-else 语句全解析
  • 上位机知识篇---流水线执行
  • KWDB初体验
  • 如何通过日志在本地调试LangChain编写的程序?
  • 聊一聊接口测试如何处理鉴权
  • 数据升降级:医疗数据的“时空穿梭“系统工程(分析与架构篇)
  • cPanelWHM 的 AutoSSL
  • 算法-堆、排序算法、矩阵乘法
  • 【C语言练习】015. 声明和初始化指针
  • 恒流源电路
  • ERC Freeze的作用与原理
  • PyTorch 2.0编译器技术深度解析:如何自动生成高性能CUDA代码
  • 2025年- H16-Lc124-169.多数元素(技巧)---java版
  • (007)Excel 公式的使用
  • Python爬虫实战:获取新浪财经最新热点文章并分析,为5月份选股做参考
  • C++初阶-string类3
  • 日期有关的算法题(ctime库的使用)
  • 盐化行业数字化转型规划详细方案(124页PPT)(文末有下载方式)
  • 跳水世界杯总决赛:程子龙/朱子锋夺男子双人10米台冠军
  • 安徽六安特色产品将“组团”入沪,借力五五购物节开拓市场
  • 5月人文社科中文原创好书榜|巫蛊:中国文化的历史暗流
  • 深交所修订创业板指数编制方案,引入ESG负面剔除机制
  • 首开股份:一季度净利润亏损约10.79亿元,签约金额63.9亿元
  • 外交部:中美双方并未就关税问题进行磋商或谈判