华为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秒
- 空间限制:256MB
- 限定语言:不限
题目描述
在斗地主扑克牌游戏中,扑克牌由小到大的顺序为:3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A, 2。玩家可以出的牌型包括单张、对子、顺子、飞机、炸弹等。
顺子的规则:
- 由至少5张连续递增的牌组成(例如:{3,4,5,6,7}或{3,4,5,…,K,A})。
- 不能包含2(如{J,Q,K,A,2}无效)。
- 不允许非连续或重复牌(如{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 7
和9 10 J Q K A
。
Java
问题分析
我们需要在斗地主游戏中找出所有可能的顺子牌型。顺子由至少5张连续递增的牌组成,不能包含2,且牌不可重复。输入为13张牌,需输出所有可能的顺子,按首个牌的大小升序排列。
解题思路
-
数据预处理:
- 将牌面转换为数值,过滤掉2。
- 去重并排序,得到有序的数值列表。
-
寻找连续序列:
- 遍历排序后的数值列表,找出所有长度≥5的连续递增序列。
-
结果转换与输出:
- 将数值序列转换回牌面,按起始牌升序输出。
代码实现
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));}}}
}
代码详细解析
-
输入处理:
- 使用
Scanner
读取输入并分割为牌面数组。
- 使用
-
牌面到数值的映射:
- 使用数组
order
定义牌面顺序,建立cardToValue
映射。
- 使用数组
-
过滤与去重:
- 遍历输入的牌,过滤掉2,并将牌面转换为数值存入
TreeSet
(自动排序并去重)。
- 遍历输入的牌,过滤掉2,并将牌面转换为数值存入
-
寻找连续序列:
- 遍历排序后的数值列表,通过比较相邻数值判断是否连续。
- 发现不连续时,若当前序列长度≥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,无法组成顺子。
综合分析
-
时间复杂度:
- 预处理:O(n),其中n为输入牌数。
- 寻找连续序列:O(m),m为去重后的牌数。
-
空间复杂度:
- 使用
TreeSet
和列表存储数值,空间复杂度为O(m)。
- 使用
-
正确性:
- 通过去重和排序确保每个顺子唯一且连续,遍历过程准确捕捉所有可能序列。
-
适用性:
- 处理任意合法输入,包括重复牌和复杂分布,确保结果正确。
python
问题分析
我们需要在斗地主游戏中找出所有可能的顺子牌型。顺子由至少5张连续递增的牌组成,不能包含2,且牌不可重复。输入为13张牌,需输出所有可能的顺子,按首个牌的大小升序排列。
解题思路
-
数据预处理:
- 将牌面转换为数值,过滤掉2。
- 去重并排序,得到有序的数值列表。
-
寻找连续序列:
- 遍历排序后的数值列表,找出所有长度≥5的连续递增序列。
-
结果转换与输出:
- 将数值序列转换回牌面,按起始牌升序输出。
代码实现
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()
代码详细解析
-
输入处理:
input().split()
读取输入并分割为牌列表。
-
牌面映射:
card_order
列表定义牌面顺序,card_value
字典将牌面映射到数值(3→0,A→11)。
-
过滤与去重:
- 遍历输入的牌,过滤掉2,转换为数值存入
values
列表,同时用集合seen
去重。 - 对
values
排序,得到升序排列的数值列表。
- 遍历输入的牌,过滤掉2,转换为数值存入
-
寻找连续序列:
- 初始化
start
记录当前连续序列的起始索引。 - 遍历数值列表,当发现不连续时,检查当前序列长度是否≥5,若是则记录。
- 示例:输入
[0,1,2,3,4,6,7,8,9,10,11]
,找到0-4
和6-11
两个序列。
- 初始化
-
结果处理:
- 若无有效序列,输出"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,无法形成顺子。
综合分析
-
时间复杂度:
- 排序:O(n log n),n为去重后的牌数(最多12种)。
- 遍历找序列:O(n),线性扫描。
- 整体复杂度为O(n log n),高效处理题目限制。
-
空间复杂度:
- 存储数值列表和序列列表,空间复杂度O(n),满足题目要求。
-
正确性:
- 去重和排序确保每个顺子唯一且连续,严格遵循顺子规则。
- 边界情况处理完善(如全为2或无足够牌)。
-
适用性:
- 直接处理输入的字符串,适应各种合法输入组合。
- 代码简洁高效,逻辑清晰易于扩展。
JavaScript
问题分析
我们需要在斗地主游戏中找出所有可能的顺子牌型。顺子由至少5张连续递增的牌组成,不能包含2,且牌不可重复。输入为13张牌,需输出所有可能的顺子,按首个牌的大小升序排列。
解题思路
-
数据预处理:
- 将牌面转换为数值(例如
3→0
,4→1
,A→11
)。 - 过滤掉所有
2
,并去重后按数值排序。
- 将牌面转换为数值(例如
-
寻找连续序列:
- 遍历排序后的数值列表,找出所有长度≥5的连续递增序列。
-
结果转换与输出:
- 将数值序列转换回牌面,按起始牌升序输出。
代码实现
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(' ')));}
});
代码详细解析
-
输入处理:
input.split(' ')
将输入字符串按空格分割为牌面数组。- 示例输入:
2 9 J 2 3 4 K A 7 9 A 5 6
→ 分割为['2', '9', 'J', ..., '6']
。
-
牌面到数值的映射:
cardOrder
定义顺序,cardValue
将牌面映射到数值(例如'3'→0
,'A'→11
)。
-
过滤与去重:
- 遍历输入牌面,过滤掉
2
,并将牌面转换为数值。 - 使用
Set
去重,确保数值唯一。 - 示例过滤后:
['9', 'J', '3', '4', ...]
→ 转换为[6, 8, 0, 1, ...]
→ 去重后排序为[0, 1, 2, 3, 4, 6, 8, 10, 11]
。
- 遍历输入牌面,过滤掉
-
寻找连续序列:
- 遍历排序后的数值,记录连续递增的起始索引
start
。 - 当发现不连续时,检查当前序列长度是否≥5。
- 示例排序后的数值
[0, 1, 2, 3, 4]
→ 记录为连续序列。
- 遍历排序后的数值,记录连续递增的起始索引
-
结果转换与输出:
- 将数值序列转换回牌面(例如
0→'3'
)。 - 按起始牌升序排序(例如
3
在9
前)。 - 输出结果,若无顺子则输出
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
综合分析
-
时间复杂度:
- 过滤和去重:O(n),线性遍历输入。
- 排序:O(m log m),m 为去重后的牌数(最多12)。
- 寻找连续序列:O(m),线性扫描。
-
空间复杂度:
- 存储数值和序列,空间复杂度为 O(m)。
-
正确性:
- 严格过滤
2
和重复牌。 - 正确检测连续递增序列,确保顺子规则。
- 严格过滤
-
适用性:
- 支持所有合法输入,处理复杂情况如多个顺子和边界条件。
C++
问题分析
需求:从13张牌中找出所有满足以下条件的顺子:
- 至少5张连续递增的牌(如3,4,5,6,7)。
- 不包含2(如J,Q,K,A,2无效)。
- 不允许重复或非连续牌(如3,4,5,6,8无效)。
输入:13张合法扑克牌(如2 9 J 2 3 4 K A 7 9 A 5 6
)。
输出:按首个牌升序输出所有顺子,无顺子则输出No
。
解题思路
- 数据预处理:
- 过滤掉所有
2
,并将牌面转换为数值(3→0,A→11)。 - 去重后按数值排序。
- 过滤掉所有
- 连续序列检测:
- 遍历排序后的数值,找出所有长度≥5的连续区间。
- 结果处理:
- 转换回牌面字符串,按起始牌升序输出。
代码实现
#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;
}
代码详细解析
- 输入处理:
split(input)
:将输入字符串分割为牌面数组(如["2", "9", "J", ...]
)。
- 牌面映射:
card_value
:建立牌面到数值的映射(如"3"→0
)。
- 过滤与去重:
unique_values
:用set
过滤掉2
并去重。
- 排序数值:
sort(values)
:将数值升序排列(如[0,1,2,3,4]
)。
- 连续序列检测:
- 遍历数值数组,维护
start
记录连续区间的起始位置。 - 当发现不连续时,若当前区间长度≥5,保存序列。
- 遍历数值数组,维护
- 结果处理:
- 将数值序列转换回牌面,并按起始牌升序排序输出。
示例测试
示例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
综合分析
-
时间复杂度:
- 过滤去重:O(n),n为输入牌数(13)。
- 排序:O(m log m),m为去重后的牌数(最多12)。
- 序列检测:O(m),线性遍历。
- 总时间复杂度:O(n + m log m),高效处理题目限制。
-
空间复杂度:
- 存储数值数组和序列结果,空间复杂度O(m)。
-
正确性:
- 严格过滤
2
和重复牌,确保连续序列的正确性。
- 严格过滤
-
适用性:
- 可处理任意合法输入,包括多个顺子或无顺子的边界情况。
C
问题分析
需求:从13张牌中找出所有满足以下条件的顺子:
- 至少5张连续递增的牌(如
3,4,5,6,7
)。 - 不包含
2
(如J,Q,K,A,2
无效)。 - 不允许重复或非连续牌(如
3,4,5,6,8
无效)。
输入:13张合法扑克牌(如 2 9 J 2 3 4 K A 7 9 A 5 6
)。
输出:按首个牌升序输出所有顺子,无顺子则输出 No
。
解题思路
- 输入处理:分割输入字符串为牌面数组。
- 牌面映射:将牌面(如
3
)映射为数值(如0
)。 - 过滤与去重:过滤掉
2
,去重后按数值排序。 - 连续序列检测:遍历数值数组,找出长度≥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;
}
代码详细解析
-
输入处理:
fgets
读取输入行,strtok
分割字符串为牌面数组。- 示例输入:
2 9 J 2 3 4 K A 7 9 A 5 6
→ 分割为["2", "9", "J", ...]
。
-
过滤与去重:
is_valid_card
判断牌是否为非2
。get_card_value
将牌面转换为数值(如"3"→0
)。contains
检查是否已存在重复值。
-
排序数值:
qsort
对数值数组升序排序。
-
连续序列检测:
- 维护
start
记录连续区间的起始位置。 - 当发现不连续时,若长度≥5,保存序列到动态数组。
- 维护
-
结果排序:
- 冒泡排序按顺子的起始牌升序排列。
-
输出处理:
- 将数值转换为牌面字符串(如
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
综合分析
-
时间复杂度:
- 过滤去重:O(n²),
contains
需要线性查找。 - 排序:O(n log n),使用快速排序。
- 序列检测:O(n),线性遍历。
- 总时间复杂度:O(n² + n log n),适用于小规模输入(n ≤13)。
- 过滤去重:O(n²),
-
空间复杂度:
- 数值数组和动态序列数组,空间复杂度为 O(n²)。
-
正确性:
- 严格过滤
2
和重复牌,正确检测连续序列。
- 严格过滤
-
适用性:
- 处理输入边界情况(如全为
2
或重复牌)。 - 动态内存管理确保资源有效利用。
- 处理输入边界情况(如全为
GO
问题分析
需求:从13张牌中找出所有满足以下条件的顺子:
- 至少5张连续递增的牌(如
3,4,5,6,7
)。 - 不包含
2
(如J,Q,K,A,2
无效)。 - 不允许重复或非连续牌(如
3,4,5,6,8
无效)。
输入:13张合法扑克牌(如 2 9 J 2 3 4 K A 7 9 A 5 6
)。
输出:按首个牌升序输出所有顺子,无顺子则输出 No
。
解题思路
- 输入处理:读取输入字符串并分割为牌面数组。
- 牌面映射:将牌面转换为数值(
3→0
,A→11
),过滤2
并去重。 - 排序数值:按数值升序排列。
- 连续序列检测:遍历排序后的数值,找出所有长度≥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, " "))}
}
代码详细解析
-
牌面映射:
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
。
- 创建牌面到数值的映射表,
-
输入处理:
scanner := bufio.NewScanner(os.Stdin) scanner.Scan() input := scanner.Text() cards := strings.Fields(input)
- 读取输入行并分割为牌面数组(如
["2", "9", "J", ...]
)。
- 读取输入行并分割为牌面数组(如
-
过滤与去重:
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
并去重,保留唯一数值。
- 过滤掉
-
排序数值:
sort.Ints(values)
- 将数值按升序排列(如
[0,1,2,3,4]
)。
- 将数值按升序排列(如
-
连续序列检测:
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的连续区间。
-
结果处理:
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
综合分析
-
时间复杂度:
- 过滤去重:O(n),线性遍历输入牌面。
- 排序:O(m log m),m为去重后的牌数(最多12)。
- 连续序列检测:O(m),线性遍历。
- 总时间复杂度:O(n + m log m),高效处理题目限制。
-
空间复杂度:
- 存储数值数组和序列结果,空间复杂度为O(m)。
-
正确性:
- 严格过滤
2
和重复牌,确保连续序列的正确性。
- 严格过滤
-
适用性:
- 处理所有合法输入,包括多个顺子或无顺子的边界情况。
- 代码简洁高效,逻辑清晰易于维护。
更多内容:
https://www.kdocs.cn/l/cvk0eoGYucWA
本文发表于【纪元A梦】,关注我,获取更多实用教程/资源!
相关文章:
华为OD机试真题——斗地主之顺子(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现
2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录…...
3.2/Q2,Charls最新文章解读
文章题目:Internet usage elevates elderly obesity: evidence from a difference-in-differences analysis of the broadband China policy DOI:10.1186/s13690-025-01565-9 中文标题:互联网使用导致老年人肥胖:中国宽带政策差异…...
Seata服务端开启事务核心源码解析
文章目录 概述一、doGlobalBegin1.1、createGlobalSession1.2、addSessionLifecycleListener1.3、begin 概述 Seata服务端作为TC角色,用于接收客户端标注了GlobalTransactional也就是TM角色的开启事务,提交/回滚事务请求,维护全局和分支事务的…...
Seata服务端回滚事务核心源码解析
文章目录 前言一、doGlobalRollback3.1、changeGlobalStatus3.2、doGlobalRollback 前言 本篇介绍Seata服务端接收到客户端TM回滚请求,进行处理并且驱动所有的RM进行回滚的源码。 一、doGlobalRollback doGlobalRollback是全局回滚的方法: 首先依旧…...
PMP-第九章 项目资源管理(一)
项目资源管理概述 项目资源管理包括识别、获取和管理所需资源以完成项目的各个过程资源主要分为实物资源和人力资源;实物资源包括设备、材料和基础设施等团队资源或人员指的是人力资源团队资源管理与项目干系人管理有重叠的部分,本章重点关注组成项目团…...
【Unity】MVP框架的使用例子
在提到MVP之前,可以先看看这篇MVC的帖子: 【Unity】MVC的简单分享以及一个在UI中使用的例子 MVC的不足之处: 在MVC的使用中,会发现View层直接调用了Model层的引用,即这两个层之间存在着一定的耦合性,而MV…...
Matlab/Simulink - BLDC直流无刷电机仿真基础教程(四) - PWM调制模拟
Matlab/Simulink - BLDC直流无刷电机仿真基础教程(四) - PWM调制模拟 前言一、PWM调制技术基本原理二、仿真模型中加入PWM调制三、逆变电路MOS管添加体二极管四、模拟添加机械负载五、仿真模型与控制框图文章相关模型文件下载链接参考链接 前言 本系列文…...
x86架构详解:定义、应用及特点
一、x86架构的定义 x86 是由Intel公司开发的复杂指令集(CISC)处理器架构,起源于1978年的Intel 8086处理器,后续扩展至32位(IA-32)和64位(x86-64)。其名称来源于早期处理器型号的“8…...
C++学习-入门到精通-【3】控制语句、赋值、自增和自减运算符
C学习-入门到精通-【3】控制语句、赋值、自增和自减运算符 控制语句、赋值、自增和自减运算符 C学习-入门到精通-【3】控制语句、赋值、自增和自减运算符一、什么是算法二、伪代码三、控制结构顺序结构选择结构if语句if...else语句switch语句 循环结构while语句 四、算法详述&a…...
【Bootstrap V4系列】学习入门教程之 页面内容排版
Bootstrap V4 学习入门教程之 页面内容排版 按钮上的指针排版一、Global settings 全局设置二、Headings 标题2.1 Customizing headings 自定义标题2.2 Display headings 显示标题2.3 Lead 引导 三、Blockquotes 块引用3.1 Naming a source 命名源3.2 Alignment 对齐 四、Lists…...
GTA5(传承/增强) 13980+真车 超跑 大型载具MOD整合包+最新GTA6大型地图MOD 5月最新更新
1500超跑载具 1000普通超跑 1500真车超跑 各种军载具1000 各种普通跑车 船舶 飞机 1000 人物1500 添加式led载具1000 超级英雄最新版 添加添加式武器MOD1000 添加地图MOD500 添加超跑载具2000 当前共计1.2wMOD 4月2日更新 新增770menyoo地图 当前共计12770 新增48款超级英雄最新…...
目标文件的段结构及核心组件详解
目标文件(如 .o 或 .obj)是编译器生成的中间文件,其结构遵循 ELF(Linux)或 COFF(Windows)格式。以下是其核心段(Section)和关键机制的详细解析: 1. 目标文件的…...
60常用控件_QSpinBox的使用
目录 代码示例:调整麦当劳购物车中的份数 使⽤ QSpinBox 或者 QDoubleSpinBox 表⽰ "微调框", 它是带有按钮的输⼊框. 可以⽤来输⼊整 数/浮点数. 通过点击按钮来修改数值⼤⼩. 由于 SpinBox 和 QDoubleSpinBox ⽤法基本相同, 就只介绍 SpinBox 的…...
数据库Mysql_约束
将失败当作自己的老师,即使他会使自己难堪 ----------陳長生. 1.什么是数据库约束 数据库约束是在数据库中对表中的内容设定条件或者规则,设置了这些规则能使得数据更具体有准确性,可靠性。 2.约束类型 NOT NULL设置列不能为空UNIQUE设置列…...
C++笔记-继承(下)(包含派生类的默认成员函数,菱形继承等)
一.派生类的默认成员函数 1.14个常见默认成员函数 默认成员函数,默认的意思就是指我们不写,编译器会自动为我们生成一个,那么在派生类中,这几个成员函数是如何生成的呢? 1.派生类的构造函数必须调用基类的构造函数初…...
DeepSeek V3 训练策略:FP8混合精度与多Token预测
近年来,大规模语言模型取得重大突破,但其训练与部署成本也随之攀升。DeepSeek 系列开源模型致力于通过优化模型结构和训练策略来降低成本、提升性能。DeepSeek V3 融合了多种先进技术(如 FP8 低精度训练、DualPipe 双流水线机制、多Token 预测目标等),在保证模型能力的同时…...
开始一个vue项目
一、创建vite项目和配置 1、查看npm版本: npm --version 根据版本选择创建命令 # npm 6.x npm create vitelatest my-vue-product --template vue # npm 7 npm create vitelatest my-vue-product -- --template vue 2、依次执行: npm install n…...
世纪华通:从财报数据看其在游戏领域的成功与未来
引言 日前,世纪华通发布了2024年及2025年第一季度的财务报告。报告显示,公司不仅在过去一年取得了显著的营收增长,而且在国内外市场均有出色表现。特别是《无尽冬日》和《Whiteout Survival》等游戏的成功,为世纪华通带来了巨大的…...
ruoyi-plus Spring Boot + MyBatis 中 BaseEntity 的设计与动态查询实践
一、BaseEntity 设计解析 以下是一个典型的 BaseEntity 设计示例: @Data public class BaseEntity implements Serializable {@Serialprivate static final long serialVersionUID =...
MCP:智能家居的“大脑”,如何引领未来居住革命
MCP:智能家居的“大脑”,如何引领未来居住革命 一、引言:MCP与智能家居的未来 随着智能家居的迅猛发展,越来越多的家庭开始拥有各种智能设备,从智能灯泡、智能门锁到智能音响,每一个设备都在为生活提供便利与舒适。然而,尽管这些设备各自具备了独立的功能,但它们之间往…...
[基础]详解C++模板类(完整实例代码)
目录 C模板类:通用编程的基石引言一、模板类的核心作用1.1 代码复用1.2 类型安全1.3 性能优化 二、模板类的进阶用法2.1 多参数模板2.2 非类型参数2.3 成员函数特化 三、实战场景解析3.1 场景一:通用容器开发3.2 场景二:算法抽象3.3 场景三&a…...
Python 常用内置函数详解(九):type()函数——获取对象类型或获取一个新的类型对象
目录 一、功能二、语法和示例 一、功能 type() 函数有两种形式,当只有一个参数时,用于获取对象的类型;当有多个参数时,用于获取新的类型对象。 二、语法和示例 第一种: type(object)参数说明: 1.object: 对象 2.…...
FreeRTOS任务管理与通信机制详解
1 任务的创建与管理 任务创建 使用 xTaskCreate() 创建任务: BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 任务函数(入口) const char * const pcName, // 任务名称(调试用) config…...
哈希表笔记(二)redis
Redis哈希表实现分析 这份代码是Redis核心数据结构之一的字典(dict)实现,本质上是一个哈希表的实现。Redis的字典结构被广泛用于各种内部数据结构,包括Redis数据库本身和哈希键类型。 核心特点 双表设计:每个字典包含两个哈希表࿰…...
专题二十一:无线局域网——WLAN
一、WLAN简介 WLAN(Wireless Local Area Network )无线局域网,使用的是 IEEE 802.11 标准系列。 标准版本发布年份最大传输速率频段Wi-Fi代数特点/描述IEEE 802.1119971–2 Mbps2.4 GHzWi-Fi 0最早的无线局域网标准,传输速率低&…...
例数据中关键指标对应的SQL查询模板
以下是针对示例数据中关键指标对应的SQL查询模板,包含MySQL和PostgreSQL两种版本: 1. 订单处理系统指标查询 1.1 订单处理成功率 -- MySQL SELECT DATE_FORMAT(created_at, %Y-%m-%d %H:%i:00) AS time_window,COUNT(*) AS total_orders,SUM(CASE WHE…...
【业务领域】电脑主板芯片电路结构
前言 由前几期视频合集(零基础自学计算机故障排除—7天了解计算机开机过程),讲解了POST的主板软启动过程;有不少网友留言、私信来问各种不开机的故障,但大多网友没能能过我们的这合集视频,很好的理清思路,那这样的情况…...
利用无事务方式插入数据库解决并发插入问题
一、背景 由于项目中同一个网元,可能会被多个不同用户操作,而且操作大部分都是以异步子任务形式进行执行,这样就会带来并发写数据问题,本文通过利用无事务方式插入数据库解决并发插入问题,算是解决问题的一种思路&…...
数字智慧方案6166丨智慧医养结合大数据平台方案(50页PPT)(文末有下载方式)
数字智慧方案6166丨智慧医养结合大数据平台方案 详细资料请看本解读文章的最后内容。 引言 随着人口老龄化的加剧,智慧医养结合的需求日益迫切。本文将对《数字智慧方案6166丨智慧医养结合大数据平台方案》进行详细解读,探讨如何通过大数据和人工智能…...
数字智慧方案5974丨智慧农业大数据应用平台综合解决方案(79页PPT)(文末有下载方式)
详细资料请看本解读文章的最后内容。 资料解读:智慧农业大数据应用平台综合解决方案 在当今数字化时代,智慧农业成为农业发展的新趋势,对提升农业生产效率、保障农产品质量、推动农业可持续发展意义重大。这份《智慧农业大数据应用平台综合解…...
补题( Convolution, 二维卷积求输出矩阵元素和最大值)
来源:https://codeforces.com/gym/105231/problem/H 题目描述: 一、题目分析 本题涉及深度学习中的二维卷积操作。给定一个nm的二维输入矩阵I和一个kl的核矩阵K ,通过特定公式计算得到(n - k 1)(m - l 1)的输出矩阵O ,要求在…...
聊一聊接口测试如何处理鉴权
目录 一、常见鉴权方式及测试方法 1. Basic Auth 2. Token 鉴权 3. OAuth 2.0 4. JWT (JSON Web Token) 5. API Key 6. HMAC 签名 7.Session-Cookie 认证 二、接口测试中的鉴权实践 1. 工具示例(Postman) 2. 代码示例(Python Requ…...
第 2.3 节: 基于 Python 的关节空间与任务空间控制
在机器人控制领域,我们通常关心两个主要的“空间”:关节空间(Joint Space)和任务空间(Task Space,也常称为操作空间 Operational Space)。关节空间描述了机器人各关节的角度或位置集合ÿ…...
[更新完毕]2025东三省A题深圳杯A题数学建模挑战赛数模思路代码文章教学:热弹性物理参数估计
完整内容请看文章最下面的推广群 热弹性物理参数估计 摘要 随着现代电子设备向高性能、微型化方向发展,芯片封装结构面临着日益严峻的热机械可靠性挑战。BGA(球栅阵列)和QFN(四方扁平无引脚)作为两种主流封装形式&am…...
【大模型面试每日一题】Day 5:GQA vs MHA效率对比
【大模型面试每日一题】Day 5:GQA vs MHA效率对比 📌 题目重现 🌟🌟 面试官:最近一些研究(如LLaMA、Mixtral)采用Grouped-Query Attention(GQA)代替传统的Multi-Head A…...
【c语言】字符函数和字符串函数
目录 1.函数介绍 1.1 strlen 1.2 strcpy 1.3 strcat 1.4 strcmp 1.5 strncpy 1.6 strncat 1.7 strncmp 1.8 strstr 1.9 strtok 1.10 strerror 1.11 memcpy 1.12 memmove 1.13 memset 编辑 1.14 memcmp C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有…...
使用 MCP(模型上下文协议)和 Claude 在 Node.js 中构建聊天应用程序
大家好,这里是架构资源栈!点击上方关注,添加“星标”,一起学习大厂前沿架构! 使用 Node.js 中的 MCP(模型上下文协议)构建聊天应用程序 我最近开发了一个简单的聊天应用程序,允许 …...
B站Michale_ee——ESP32_IDF SDK——FreeRTOS_2 队列
一、通过队列传递三种类型数据(整型、结构体、指针) 1.队列简介 FreeRTOS中的队列本质就是一个先入先出的缓冲区(FIFO,First Input First Output) 2.API简介 (1)创建队列的API (…...
小米MiMo:7B模型逆袭AI大模型战场的技术密码
小米MiMo:7B模型逆袭AI大模型战场的技术密码 在大模型竞争愈发激烈的2025年4月30日,小米以一款名为 MiMo-7B 的开源模型强势突围,在数学推理与代码能力评测中表现亮眼,不仅与规模更大的模型正面对抗,甚至超越了 OpenA…...
Java关键字解析
Java关键字是编程语言中具有特殊含义的保留字,不能用作标识符(如变量名、类名等)。Java共有50多个关键字(不同版本略有差异),下面我将分类详细介绍这些关键字及其使用方式。 一、数据类型相关关键字 1. 基…...
YOLOv8模型训练过程
一,conda环境的创建就略过了 先进行库工具安装 pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple 二,在github上下载好模型,先预测一把 yolo predict modelyolov8n.pt sourceultralytics/assets/bus.jpg 如果无…...
1996-2022年全国31省ZF干预度数据/财政干预度数据(含原始数据+计算过程+结果)
1996-2022年全国31省ZF干预度数据/财政干预度数据(含原始数据计算过程结果) 1、时间:1996-2022年 2、来源:国家统计局和各省年鉴 3、指标:地方财政一般预算支出、地区生产总值(GDP)、ZF干预度…...
STM32移植U8G2
STM32 移植 U8G2 u8g2 (Universal 8bit Graphics Library version2 的缩写)是用于嵌入式设备的单色图形库,可以在单色屏幕中绘制 GUI。u8g2 内部附带了例如 SSD13xx,ST7xx 等很多 OLED,LCD 驱动。内置多种不同大小和风…...
26.电流信号的强抗干扰能力运用
电流信号强抗干扰能力运用 1. 电流型信号与电压型信号的传输抗干扰能力差异2. 电流型信号电路示例 1. 电流型信号与电压型信号的传输抗干扰能力差异 现场干扰以电场干扰为主,电压较高但是能量(电流I)较低。如果以能量信号作为传输媒介&#x…...
【 Node.js】 Node.js安装
下载 下载 | Node.js 中文网https://nodejs.cn/download/ 安装 双击安装包 点击Next 勾选使用许可协议,点击Next 选择安装位置 点击Next 点击Next 点击Install 点击Finish 完成安装 添加环境变量 编辑【系统变量】下的变量【Path】添加Node.js的安装路径--如果…...
经典算法 青蛙跳杯子
青蛙跳杯子 题目描述 桌子上有n行m列的杯子,每个杯子与相邻杯子之间的距离为1,已知青蛙的跳跃半径为d,青蛙现在在第一行第一列的杯子上,它跳到最后一行最后一列的杯子上,最少需要跳几次? 输入描述 输入…...
C语言-函数的递归和迭代
以下是我初学C语言的笔记记录,欢迎在评论区补充留言 一,函数的递归 大致有这么几个问题【我看完这堂课后,自己总结的几个问题】 * 问题 1,什么是函数的递归, 2,它是干什么用的,3,有什么条件吗…...
Linux安装部署Postgresql数据库
联网安装方案 Linux能在线安装依赖组件的前提下,可以快速安装部署PG数据库,安装过程使用root管理员帐号: 首先,使用如下命令自动下载Postgresql组件: # 在openEuler、Fedora或CentOS 8上,你可能会使用&a…...
学习与规划的融合Dyna-Q:python从零实现
🧠 向所有学习者致敬! “学习不是装满一桶水,而是点燃一把火。” —— 叶芝 我的博客主页: https://lizheng.blog.csdn.net 🌐 欢迎点击加入AI人工智能社区! 🚀 让我们一起努力,共创…...
电子病历高质量语料库构建方法与架构项目(环境聆听与自动化文档生成篇)
电子病历高质量语料库的构建是一个复杂而系统的工程,涉及数据收集、清洗、标注、验证等多个环节。在项目实施过程中,"环境聆听"和"自动化文档生成"是两个关键支撑要素,前者确保项目能够适应不断变化的技术和业务环境,后者则保障项目过程的可追溯性和知…...