华为OD机试-2024年E卷-斗地主之顺子
题目描述
在斗地主只扑克牌游戏中,扑克牌由小到大的顺序为: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}都是有效的顺子;而{,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 1 0 3 4 K A 7 Q A 5 6
输出
3 4 5 6 7
9 10 J Q K A
说明
13张牌中,可以组成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
说明
13张牌中,无法组成顺子。
题目分析:
- 扑克牌按从小到大的顺序排列为:3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A。牌 2 不能用于顺子。
- 顺子的规则是:至少由5张连续递增的牌组成,例如 (3, 4, 5, 6, 7)。
- 需要找出所有可能的顺子组合,每个顺子中的牌不能重复使用。
解题思路
1、输入准备:
- 从输入中读取13张扑克牌,存储在一个列表或数组中。
2、数据转换:
- 将扑克牌的字符表示(如 "J", "Q", "K", "A")转换为对应的数字值,以便于排序和比较。
- 排除不能用于顺子的牌 2。
3、排序:
- 对转换后的牌进行排序,以便更容易查找连续递增的序列。
4、查找顺子:
- 初始化数据结构:创建一个布尔数组(或列表)used,初始化为false,- 用于跟踪每张牌是否已经被用作某个顺子的一部分。
- 遍历牌序列:使用两层循环:
- 外层循环从每一张未使用的牌作为起点开始。
- 内层循环尝试构建一个顺子:
- 如果下一张牌与当前顺子的最后一张牌连续且未被使用,添加到当前顺子中并标记为已使用。
- 如果不连续或已被使用,终止当前顺子的构建。
- 验证顺子长度:检查构建的顺子是否至少包含5张牌:
- 如果是,将该顺子保存起来。
- 如果不是,重置used数组中与当前顺子相关的牌的标记,使它们可以用于后续的顺子构建。
5、输出结果:
- 如果找到一个或多个顺子,按顺序输出它们。
- 如果没有找到任何顺子,输出 "NO"。
c++源代码:
#include <iostream> #include <vector> #include <algorithm> #include <unordered_map> using namespace std; // 将扑克牌转换为对应的数字值 int cardValue(const string &card) { if (card == "3") return 3; if (card == "4") return 4; if (card == "5") return 5; if (card == "6") return 6; if (card == "7") return 7; if (card == "8") return 8; if (card == "9") return 9; if (card == "10") return 10; if (card == "J") return 11; if (card == "Q") return 12; if (card == "K") return 13; if (card == "A") return 14; return 0; // 忽略 '2' } int main() { vector<string> cards(13); for (int i = 0; i < 13; ++i) { cin >> cards[i]; } // 转换并排序卡片,排除 '2' vector<int> cardNumbers; for (const auto &card : cards) { int value = cardValue(card); if (value != 0) { // 跳过 '2' cardNumbers.push_back(value); } } sort(cardNumbers.begin(), cardNumbers.end()); vector<vector<int>> sequences; vector<bool> used(cardNumbers.size(), false); // 记录每张牌是否已被使用 // 查找所有可能的顺子 for (int i = 0; i < cardNumbers.size(); ++i) { if (used[i]) continue; // 已使用的牌跳过 vector<int> currentSequence; currentSequence.push_back(cardNumbers[i]); used[i] = true; // 标记当前牌已使用 for (int j = i + 1; j < cardNumbers.size(); ++j) { if (used[j]) continue; // 跳过已使用的牌 if (cardNumbers[j] == currentSequence.back() + 1) { currentSequence.push_back(cardNumbers[j]); used[j] = true; // 标记当前牌已使用 } else if (cardNumbers[j] > currentSequence.back() + 1) { break; // 不再连续,结束当前顺子的查找 } } if (currentSequence.size() >= 5) { sequences.push_back(currentSequence); } else { // 如果当前顺子不满足要求,重置已使用标记 for (int k = 0; k < currentSequence.size(); ++k) { auto it = find(cardNumbers.begin(), cardNumbers.end(), currentSequence[k]); if (it != cardNumbers.end()) { used[it - cardNumbers.begin()] = false; } } } } // 输出结果 if (sequences.empty()) { cout << "No" << endl; } else { for (const auto &seq : sequences) { for (int i = 0; i < seq.size(); ++i) { if (i > 0) cout << " "; cout << (seq[i] > 10 ? (seq[i] == 11 ? "J" : seq[i] == 12 ? "Q" : seq[i] == 13 ? "K" : "A") : to_string(seq[i])); } cout << endl; } } return 0; }
Java源代码:
import java.util.*; public class Main { // 将扑克牌转换为对应的数字值 private static int cardValue(String card) { switch (card) { case "3": return 3; case "4": return 4; case "5": return 5; case "6": return 6; case "7": return 7; case "8": return 8; case "9": return 9; case "10": return 10; case "J": return 11; case "Q": return 12; case "K": return 13; case "A": return 14; default: return 0; // 忽略 '2' } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String[] inputCards = new String[13]; for (int i = 0; i < 13; i++) { inputCards[i] = scanner.next(); } scanner.close(); // 转换并排序卡片,排除 '2' List<Integer> cardNumbers = new ArrayList<>(); for (String card : inputCards) { int value = cardValue(card); if (value != 0) { // 跳过 '2' cardNumbers.add(value); } } Collections.sort(cardNumbers); List<List<Integer>> sequences = new ArrayList<>(); boolean[] used = new boolean[cardNumbers.size()]; // 记录每张牌是否已被使用 // 查找所有可能的顺子 for (int i = 0; i < cardNumbers.size(); i++) { if (used[i]) continue; // 已使用的牌跳过 List<Integer> currentSequence = new ArrayList<>(); currentSequence.add(cardNumbers.get(i)); used[i] = true; // 标记当前牌已使用 for (int j = i + 1; j < cardNumbers.size(); j++) { if (used[j]) continue; // 跳过已使用的牌 if (cardNumbers.get(j) == currentSequence.get(currentSequence.size() - 1) + 1) { currentSequence.add(cardNumbers.get(j)); used[j] = true; // 标记当前牌已使用 } else if (cardNumbers.get(j) > currentSequence.get(currentSequence.size() - 1) + 1) { break; // 不再连续,结束当前顺子的查找 } } if (currentSequence.size() >= 5) { sequences.add(new ArrayList<>(currentSequence)); } else { // 如果当前顺子不满足要求,重置已使用标记 for (Integer num : currentSequence) { used[cardNumbers.indexOf(num)] = false; } } } // 输出结果 if (sequences.isEmpty()) { System.out.println("No"); } else { for (List<Integer> seq : sequences) { for (int i = 0; i < seq.size(); i++) { if (i > 0) System.out.print(" "); int value = seq.get(i); if (value == 11) System.out.print("J"); else if (value == 12) System.out.print("Q"); else if (value == 13) System.out.print("K"); else if (value == 14) System.out.print("A"); else System.out.print(value); } System.out.println(); } } } }
python源代码:
def card_value(card): """将扑克牌转换为对应的数字值""" card_map = { "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, "10": 10, "J": 11, "Q": 12, "K": 13, "A": 14 } return card_map.get(card, 0) # 忽略 '2' def find_sequences(card_numbers): """查找所有可能的顺子""" sequences = [] used = [False] * len(card_numbers) # 记录每张牌是否已被使用 for i in range(len(card_numbers)): if used[i]: continue # 已使用的牌跳过 current_sequence = [card_numbers[i]] used[i] = True # 标记当前牌已使用 for j in range(i + 1, len(card_numbers)): if used[j]: continue # 跳过已使用的牌 if card_numbers[j] == current_sequence[-1] + 1: current_sequence.append(card_numbers[j]) used[j] = True # 标记当前牌已使用 elif card_numbers[j] > current_sequence[-1] + 1: break # 不再连续,结束当前顺子的查找 if len(current_sequence) >= 5: sequences.append(current_sequence) else: # 如果当前顺子不满足要求,重置已使用标记 for num in current_sequence: used[card_numbers.index(num)] = False return sequences def main(): input_cards = input().split() # 转换并排序卡片,排除 '2' card_numbers = [card_value(card) for card in input_cards if card_value(card) != 0] card_numbers.sort() # 查找所有顺子 sequences = find_sequences(card_numbers) # 输出结果 if not sequences: print("No") else: for seq in sequences: output_seq = [] for value in seq: if value == 11: output_seq.append("J") elif value == 12: output_seq.append("Q") elif value == 13: output_seq.append("K") elif value == 14: output_seq.append("A") else: output_seq.append(str(value)) print(" ".join(output_seq)) if __name__ == "__main__": main()#华为od##华为od机试##华为##华为工作体验#