2025 B卷 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)) {
// 忽略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));
}
}
}
}
代码详细解析
-
输入处理:
- 使用
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: # 过滤掉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 =