牛客网4874题:用哈希表解决扑克牌比大小
一、题目解读
牛客网4874题要求实现一个扑克牌比较算法,输入两手牌(如"3-4-5"与"JOKER-JOKER"),判断其胜负关系。题目涉及多种牌型优先级:对王(大小王对子)>炸弹(四张相同牌)>顺子(五张连续牌)>三个、对子、个子,且需处理错误输入格式。核心挑战在于高效判断牌型并比较权重,确保逻辑严谨性与代码性能。
二、解题思路
1. 数据结构优化:使用unordered_map将牌面值(如"3"、"J")映射为数值权重(1-15),避免字符串比较耗时,加速牌型判断。
2. 枚举牌型:定义CardType枚举简化牌型分类,便于后续逻辑分支与权重赋值。
3. 分情况讨论:按牌数量(2/3/4/5)逐级判断对王、炸弹、顺子等特殊牌型,减少冗余计算。
4. 权重比较:牌型优先级通过枚举值隐式排序(如JOKER_PAIR=15最高),相同牌型则比较首牌权重。
5. 错误处理:输入格式错误时返回"ERROR",增强程序鲁棒性。
三、解题步骤
1. 输入解析:通过find('-')定位分隔符,分割两手牌字符串为子串数组。
2. 牌型与权重获取:调用getCardType()函数,根据牌数量及连续性判断牌型,返回<牌型枚举, 权重>。
3. 比较逻辑:若牌型不同,直接比较枚举值;若相同,则比较权重(如炸弹比较四张牌的数值)。
4. 输出结果:根据比较结果返回胜负标识(如"胜"、"负"、"平")。
四、代码和注释
#include <iostream> #include <vector> #include <string> #include <unordered_map> #include <sstream> #include <algorithm> using namespace std; // 扑克牌权重映射表(优化比较效率) const unordered_map<string, int> CARD_RANK = { {"3", 1}, {"4", 2}, {"5", 3}, {"6", 4}, {"7", 5}, {"8", 6}, {"9", 7}, {"10", 8}, {"J", 9}, {"Q", 10}, {"K", 11}, {"A", 12}, {"2", 13}, {"joker", 14}, {"JOKER", 15} }; // 牌型枚举 enum CardType { SINGLE = 1, // 单个 PAIR, // 对子 TRIPLE, // 三个 BOMB, // 炸弹 STRAIGHT, // 顺子 JOKER_PAIR // 对王 }; // 核心函数:根据牌列表返回牌型与权重 pair<CardType, int> getCardType(const vector<string>& cards) { int size = cards.size(); // 对王判断(最高优先级) if (size == 2 && cards[0] == "joker" && cards[1] == "JOKER") { return {JOKER_PAIR, 15}; } // 炸弹判断(四张相同) if (size == 4 && all_of(cards.begin(), cards.end(), [&](const string& s){return s == cards[0];})) { return {BOMB, CARD_RANK.at(cards[0])}; } // 顺子判断(五张连续) if (size == 5) { bool is_straight = true; for (int i = 0; i < 4; ++i) { if (CARD_RANK.at(cards[i+1]) - CARD_RANK.at(cards[i])!= 1) { is_straight = false; break; } } if (is_straight) { return {STRAIGHT, CARD_RANK.at(cards[0])}; } } // 三个、对子、个子判断(逐级递减) if (size == 3 && cards[0] == cards[1] && cards[1] == cards[2]) { return {TRIPLE, CARD_RANK.at(cards[0])}; } if (size == 2 && cards[0] == cards[1]) { return {PAIR, CARD_RANK.at(cards[0])}; } return {SINGLE, CARD_RANK.at(cards[0])}; } // 比较两手牌 string compareCards(const string& input) { size_t pos = input.find('-'); if (pos == string::npos) return "ERROR"; vector<string> cards1, cards2; istringstream iss(input.substr(0, pos)); string card; while (iss >> card) cards1.push_back(card); iss = istringstream(input.substr(pos + 1)); while (iss >> card) cards2.push_back(card); auto [type1, rank1] = getCardType(cards1); auto [type2, rank2] = getCardType(cards2); // 处理特殊牌型 if (type1 == JOKER_PAIR) return input.substr(0, pos); if (type2 == JOKER_PAIR) return input.substr(pos + 1); if (type1 == BOMB && type2 != BOMB) return input.substr(0, pos); if (type2 == BOMB && type1 != BOMB) return input.substr(pos + 1); // 同类型比较 if (type1 == type2) { return (rank1 > rank2) ? input.substr(0, pos) : input.substr(pos + 1); } return "ERROR"; } int main() { string input; getline(cin, input); cout << compareCards(input) << endl; return 0; }
五、总结
本文代码通过以下策略高效解决扑克牌比较问题:
● 利用哈希表与枚举类型实现O(1)牌值映射与牌型分类;
● 分治思想简化逻辑复杂度,优先处理高优先级牌型;
● 结合all_of、find等算法库函数提升代码简洁性;
● 严谨的错误处理增强实用性。
该算法为棋牌类游戏开发中的牌型判定提供了可复用的模板,亦展示了数据结构选择与逻辑分层对算法性能的关键影响。
原创内容 转载请注明出处