一、题目描述
斗地主起源于湖北十堰房县,据说是一位叫吴修全的年轻人根据当地流行的扑克玩法"跑得快"改编的,如今已风靡整个中国,并流行于互联网上。
牌型:单顺,又称顺子,最少5张牌,最多12张牌(3...A)不能有2,也不能有大小王,不计花色。 例:3-4-5-6-7-8,7-8-9-10-J-Q,3-4-5-6-7-8-9-10-J-Q-K-A可用的牌3<4<5<6<7<8<9<10<J<Q<K<A<2<B(小王)C(大王),每种牌除大小王外有四种花色(共有13x4+2张牌)。
1、输入
手上有的牌
已经出过的牌(包括对手出的和自己出的牌)
2、输出
对手可能构成的最长的顺子(如果有相同长度的顺子,输出牌面最大的那一个) 如果无法构成顺子,则输出NO-CHAIN
二、输入描述
输入的第一行为当前手中的牌
输入的第二行为已经出过的牌
三、输出描述
最长的顺子
输入输出说明
3-3-3-3-4-4-5-5-6-7-8-9-10-J-Q-K-A
A-4-5-6-7-8-8-8 9-10-J-Q-K-A
四、测试用例
1、输入
3-3-4-4-5-A-5-6-2-8-3-9-10-Q-7-K-J-10-B
A-4-5-8-8-10-C-6-7-8
2、输出
9-10-J-Q-K-A
3、说明
拼接两个字符串,排除掉不能成龙的2和大小王;
3, 3, 4, 4, 5, 14, 5, 6, 8, 3, 9, 10, 12, 7, 13, 11, 10, 14, 4, 5, 8, 8, 10, 6, 7, 8
获取对手的牌,{3=1, 4=1, 5=1, 6=2, 7=2, 8=0, 9=3, 10=1, 11=3, 12=3, 13=3, 14=2};
获取对手的牌能组成的最大的龙,[14, 13, 12, 11, 10, 9];
数值映射转换9-10-J-Q-K-A。
java
package com.study.algorithm.huaweiOrOD.huaweiOD202509082334.华为OD机试2024E卷最长的顺子;
import java.util.*;
/**
* @ProjectName: algorithm
* @ClassName: Main
* @Description: 华为OD机试真题 - 最长的顺子 - 2024E卷 Java
* @Author: Tony_Yi
* @Date: 2025/11/17 23:10
* @Version 1.0
**/
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String handCards = sc.nextLine();//自己手上的牌
String playedCards = sc.nextLine();//已经出过的牌
String result = findLongestStraight(handCards, playedCards);//寻找最长的顺子
System.out.println(result);//输出结果
}
private static String findLongestStraight(String handCards, String playedCards) {
//1.合并所有已知的牌(手上的牌+已出的牌)
String allKnownCards = handCards + "-" + playedCards;
String[] cardArray = allKnownCards.split("-");
//2.统计每张牌出现的次数(排除2和大小王)
Map<String, Integer> cardCount = new HashMap<>();
//3.初始化所有可能的顺子牌(3-A)
String[] possibleCards = new String[]{"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"};
for (String card : possibleCards) {
cardCount.put(card, 0);
}
// 统计已知牌中每张牌出现的次数
for (String card : cardArray) {
if (card.equals("2") || card.equals("B") || card.equals("C")) {
continue;
}
if (cardCount.containsKey(card)) {
cardCount.put(card, cardCount.get(card) + 1);
}
}
// 4.计算对手可能拥有的牌(每张牌最多4张)
Map<String, Integer> opponentCards = new HashMap<>();
for (String card : possibleCards) {
Integer knownCount = cardCount.get(card);
int opponentCount = 4 - knownCount;
opponentCards.put(card, opponentCount);
}
// 4.寻找最长的顺子
List<String> longestStraight = new ArrayList<>();
// 将牌面转换为数值便于比较
Map<String, Integer> cardValues = createCardValueMap();
// 尝试所有可能的顺子起点
for (int i = 0; i < possibleCards.length; i++) {
List<String> currentStraight = new ArrayList<>();
for (int j = i; j < possibleCards.length; j++) {
String currentCard = possibleCards[j];
if (opponentCards.get(currentCard) > 0) {
currentStraight.add(currentCard);
// 如果对手也拥有这张牌,可以加入顺子
if (currentStraight.size() >= 5) {
if (currentStraight.size() > longestStraight.size() || (currentStraight.size() == longestStraight.size() && isLargerStraight(currentStraight, longestStraight, cardValues))) {
longestStraight = new ArrayList<>(currentStraight);
}
}
} else {
// 如果对手没有这张牌,顺子中断
break;
}
}
}
// 5.输出结果
if (longestStraight.size() >= 5) {
return String.join("-", longestStraight);
} else {
return "NO-CHAIN";
}
}
/**
* 创建牌面到数值的映射
* 3=3, 4=4, ..., 10=10, J=11, Q=12, K=13, A=14
*/
private static Map<String, Integer> createCardValueMap() {
Map<String, Integer> cardValues = new HashMap<>();
cardValues.put("3", 3);
cardValues.put("4", 3);
cardValues.put("5", 3);
cardValues.put("6", 3);
cardValues.put("7", 3);
cardValues.put("8", 3);
cardValues.put("9", 3);
cardValues.put("10", 3);
cardValues.put("J", 3);
cardValues.put("Q", 3);
cardValues.put("K", 3);
cardValues.put("A", 3);
return cardValues;
}
/**
* 判断顺子currentStraight是否比longestStraight更大
* 规则:比较顺子的最大牌,如果最大牌相同则比较次大牌,以此类推
*/
private static boolean isLargerStraight(List<String> currentStraight, List<String> longestStraight, Map<String, Integer> cardValues) {
if (longestStraight.isEmpty()) {
return true;
}
// 比较两张顺子的最大牌
String maxCard1 = currentStraight.get(currentStraight.size() - 1);
String maxCard2 = longestStraight.get(longestStraight.size() - 1);
Integer value1 = cardValues.get(maxCard1);
Integer value2 = cardValues.get(maxCard2);
if (value1 != value2) {
return value1 > value2;
}
// 如果最大牌相同,比较长度
if (currentStraight.size() != longestStraight.size()) {
return currentStraight.size() > longestStraight.size();
}
// 长度也相同,比较次大牌(实际上这种情况不会出现,因为最大牌相同且长度相同的顺子是完全相同的)
return true;
}
}