#P2992. 最长的顺子(100分)
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 367
            Accepted: 102
            Difficulty: 6
            
          
          
          
                       所属公司 : 
                              华为od
                                
            
                      
          
 
- 
                        算法标签>模拟          
 
最长的顺子(100分)
题面描述
斗地主起源于湖北十堰房县,据说是一位叫吴修全的年轻人根据当地流行的扑克玩法“跑得快”改编的,如今已风靡整个中国,并流行于互联网上。
牌型:单顺,又称顺子,最少 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(大王)$,每种牌除大小王外有四种花色(共有 13×4+2=54 张牌)。
思路
- 
牌面表示:
- 将牌面转化为数字表示,便于比较和排序。按照给定的顺序,
3到A分别对应0到11,2对应12,小王和大王分别对应13和14。由于顺子不能包含2、小王和大王,因此有效牌面范围为0到11。 
 - 将牌面转化为数字表示,便于比较和排序。按照给定的顺序,
 - 
计算剩余牌:
- 总牌数为每种牌4张(不包括大小王),需要从总牌中减去手中持有的牌和已出过的牌,得到剩余对手可能持有的牌。
 
 - 
统计牌面:
- 统计剩余牌中每种牌的数量。如果某种牌的剩余数量大于0,说明对手可能持有该牌。
 
 - 
寻找最长顺子:
- 遍历从 
3到A的所有可能的连续序列。 - 对于每一个可能的起始点,尝试尽可能延长顺子的长度,确保每张牌至少存在一张。
 - 记录所有可能的顺子,选择最长的那个。如果有多个长度相同的顺子,选择牌面最大的。
 
 - 遍历从 
 - 
输出结果:
- 根据找到的最长顺子输出对应的牌面,如果无法找到符合条件的顺子,输出 
NO-CHAIN。 
 - 根据找到的最长顺子输出对应的牌面,如果无法找到符合条件的顺子,输出 
 
cpp
#include <bits/stdc++.h>
using namespace std;
// 牌面到数字的映射
unordered_map<string, int> 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",12}, {"B",13}, {"C",14}
};
// 数字到牌面的映射
string num_to_card(int num){
    vector<string> cards = {"3","4","5","6","7","8","9","10","J","Q","K","A","2","B","C"};
    return cards[num];
}
int main(){
    string hand, played;
    // 读取手牌和已出牌
    cin >> hand;
    cin >> played;
    
    // 统计所有牌的数量(每种牌4张,大小王各1张)
    int total_cards[15];
    memset(total_cards, 0, sizeof(total_cards));
    for(int i=0;i<=14;i++) {
        if(i < 13) total_cards[i] = 4;
        else total_cards[i] =1;
    }
    
    // 统计手牌
    string token;
    stringstream ss(hand);
    while(getline(ss, token, '-')){
        if(card_map.find(token) != card_map.end())
            total_cards[card_map[token]]--;
    }
    
    // 统计已出牌
    stringstream ss2(played);
    while(getline(ss2, token, '-')){
        if(card_map.find(token) != card_map.end())
            total_cards[card_map[token]]--;
    }
    
    // 构建剩余牌的存在性,仅考虑3到A(0到11)
    bool available[12]; // 0到11对应3到A
    for(int i=0;i<12;i++) {
        available[i] = (total_cards[i] >0);
    }
    
    // 寻找最长顺子
    int max_len = 0;
    int max_end = -1;
    for(int start=0; start <= 11-4; start++){ // 最少5张
        if(!available[start]) continue;
        int current = start;
        int len =1;
        while(current +1 <12 && available[current+1]){
            current++;
            len++;
        }
        if(len >=5){
            if(len > max_len || (len == max_len && current > max_end)){
                max_len = len;
                max_end = current;
            }
        }
    }
    
    if(max_len >=5){
        // 输出从 (max_end - max_len +1) 到 max_end
        int start = max_end - max_len +1;
        string res = "";
        for(int i=start;i<=max_end;i++){
            res += num_to_card(i);
            if(i != max_end) res += "-";
        }
        cout << res;
    }
    else{
        cout << "NO-CHAIN";
    }
}
python
# 牌面到数字的映射
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":12, "B":13, "C":14
}
# 数字到牌面的映射
num_to_card = ["3","4","5","6","7","8","9","10","J","Q","K","A","2","B","C"]
def main():
    import sys
    hand = sys.stdin.readline().strip()
    played = sys.stdin.readline().strip()
    
    # 初始化牌的总数量
    total_cards = [4]*13 + [1,1] # 0-12为3-2,13和14为大小王
    
    # 统计手牌
    for card in hand.split('-'):
        if card in card_map:
            total_cards[card_map[card]] -=1
    
    # 统计已出牌
    for card in played.split('-'):
        if card in card_map:
            total_cards[card_map[card]] -=1
    
    # 构建剩余牌的存在性,仅考虑3到A(0到11)
    available = [total_cards[i]>0 for i in range(12)] # 0到11对应3到A
    
    max_len = 0
    max_end = -1
    for start in range(0, 12-4):
        if not available[start]:
            continue
        current = start
        length =1
        while current +1 <12 and available[current+1]:
            current +=1
            length +=1
        if length >=5:
            if length > max_len or (length == max_len and current > max_end):
                max_len = length
                max_end = current
    if max_len >=5:
        start = max_end - max_len +1
        chain = '-'.join(num_to_card[i] for i in range(start, max_end+1))
        print(chain)
    else:
        print("NO-CHAIN")
if __name__ == "__main__":
    main()
java
import java.util.*;
public class Main {
    // 牌面到数字的映射
    static Map<String, Integer> cardMap = new HashMap<>();
    static String[] numToCard = {"3","4","5","6","7","8","9","10","J","Q","K","A","2","B","C"};
    static {
        String[] cards = {"3","4","5","6","7","8","9","10","J","Q","K","A","2","B","C"};
        for(int i=0;i<cards.length;i++) {
            cardMap.put(cards[i], i);
        }
    }
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String hand = sc.next();
        String played = sc.next();
        
        // 初始化牌的总数量
        int[] totalCards = new int[15];
        for(int i=0;i<13;i++) totalCards[i] =4;
        totalCards[13] =1; // 小王
        totalCards[14] =1; // 大王
        
        // 统计手牌
        String[] handCards = hand.split("-");
        for(String card: handCards){
            if(cardMap.containsKey(card))
                totalCards[cardMap.get(card)]--;
        }
        
        // 统计已出牌
        String[] playedCards = played.split("-");
        for(String card: playedCards){
            if(cardMap.containsKey(card))
                totalCards[cardMap.get(card)]--;
        }
        
        // 构建剩余牌的存在性,仅考虑3到A(0到11)
        boolean[] available = new boolean[12];
        for(int i=0;i<12;i++) {
            available[i] = (totalCards[i] >0);
        }
        
        // 寻找最长顺子
        int maxLen =0;
        int maxEnd = -1;
        for(int start=0; start <= 11-4; start++){
            if(!available[start]) continue;
            int current = start;
            int len =1;
            while(current +1 <12 && available[current+1]){
                current++;
                len++;
            }
            if(len >=5){
                if(len > maxLen || (len == maxLen && current > maxEnd)){
                    maxLen = len;
                    maxEnd = current;
                }
            }
        }
        
        if(maxLen >=5){
            int start = maxEnd - maxLen +1;
            StringBuilder sb = new StringBuilder();
            for(int i=start;i<=maxEnd;i++){
                sb.append(numToCard[i]);
                if(i != maxEnd) sb.append("-");
            }
            System.out.println(sb.toString());
        }
        else{
            System.out.println("NO-CHAIN");
        }
    }
}
        题目内容
斗地主起源于湖北十堰房县,据说是一位叫吴修全的年轻人根据当地流行的扑克玩法“跑得快”改编的,如今已风靡整个中国,并流行于互联网上。
牌型:单顺,又称顺子,最少 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(大王),每种牌除大小王外有四种花色
(共有 13×4+2 张牌)
输入:
手上有的牌
已经出过的牌(包括对手出的和自己出的牌)
输出:
对手可能构成的最长的顺子(如果有相同长度的顺子,输出牌面最大的那一个), 如果无法构成顺子,则输出 NO−CHAIN。
输入描述
输入的第一行为当前手中的牌
输入的第二行为已经出过的牌
输出描述
最长的顺子
样例1
输入
3-3-3-3-4-4-5-5-6-7-8-9-10-J-Q-K-A
4-5-6-7-8-8-8
输出
9-10-J-Q-K-A
样例2
输入
3-3-3-3-8-8-8-8
K-K-K-K
输出
NO-CHAIN
说明
剩余的牌无法构成顺子