一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情。
描述
扑克牌游戏大家应该都比较熟悉了,一副牌由54张组成,含3~A、2各4张,小王1张,大王1张。牌面从小到大用如下字符和字符串表示(其中,小写joker表示小王,大写JOKER表示大王):
3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
输入两手牌,两手牌之间用"-"连接,每手牌的每张牌以空格分隔,"-"两边没有空格,如:4 4 4 4-joker JOKER。
请比较两手牌大小,输出较大的牌,如果不存在比较关系则输出ERROR。
基本规则:
(1)输入每手牌可能是个子、对子、顺子(连续5张)、三个、炸弹(四个)和对王中的一种,不存在其他情况,由输入保证两手牌都是合法的,顺子已经从小到大排列;
(2)除了炸弹和对王可以和所有牌比较之外,其他类型的牌只能跟相同类型的存在比较关系(如,对子跟对子比较,三个跟三个比较),不考虑拆牌情况(如:将对子拆分成个子);
(3)大小规则跟大家平时了解的常见规则相同,个子、对子、三个比较牌面大小;顺子比较最小牌大小;炸弹大于前面所有的牌,炸弹之间比较牌面大小;对王是最大的牌;
(4)输入的两手牌不会出现相等的情况。
数据范围:字符串长度:3≤s≤10
输入描述:
输入两手牌,两手牌之间用"-"连接,每手牌的每张牌以空格分隔,"-"两边没有空格,如 4 4 4 4-joker JOKER。
输出描述:
输出两手牌中较大的那手,不含连接符,扑克牌顺序不变,仍以空格隔开;如果不存在比较关系则输出ERROR。
示例1
输入:
4 4 4 4-joker JOKER
输出:
joker JOKER
题目的主要信息:
-
输入两手牌,两手牌之间用"-"连接,每手牌的每张牌以空格分隔,"-"两边没有空格
-
比较两手牌大小,输出较大的牌,如果不存在比较关系则输出ERROR
-
比较规则如下:
- 输入每手牌可能是个子、对子、顺子(连续5张)、三个、炸弹(四个)和对王中的一种,不存在其他情况,由输入保证两手牌都是合法的,顺子已经从小到大排列;
- 除了炸弹和对王可以和所有牌比较之外,其他类型的牌只能跟相同类型的存在比较关系,不考虑拆牌情况;
- 个子、对子、三个比较牌面大小,顺子比较最小牌大小,炸弹大于前面所有的牌,炸弹之间比较牌面大小,对王是最大的牌;
- 输入的两手牌不会出现相等的情况
方法一:空格统计法
具体做法:
首先读入的一行手牌根据“-”截取成两副手牌,然后遍历两副手牌,然后我们遍历两副手牌寻找各自的空格数,因为个子是一张牌无空格,对子是两张牌一个空格,顺子是5张牌4个空格,三个是3张牌2个空格,炸弹是4张牌3个空格,如果王炸单独比较,那么每种类型的牌字符串中空格数都不一样。
然后查看要比较的两个字符串,如果任意一方有王炸,直接输出王炸即可。然后我们就看查看两个字符串空格数是否为3,就是是否有炸弹,如果都有炸弹,比较牌面后输出,否则输出有炸弹的一方。
对于剩余的类型,只有空格数相等才能比较,否则不可以比较,比较的时候直接比较第一张牌的牌面值即可,比较的时候我们给13张牌从3到2定义1到13的大小等级,通过返回的大小等级比较大小,其中10用1代替。
#include<iostream>
#include<string>
using namespace std;
int getvalue(string s){ //根据输入的字符首字母输出大小等级
switch(s[0]){
case '3': return 1;
case '4': return 2;
case '5': return 3;
case '6': return 4;
case '7': return 5;
case '8': return 6;
case '9': return 7;
case '1': return 8; //用1代替10
case 'J': return 9;
case 'Q': return 10;
case 'K': return 11;
case 'A': return 12;
case '2': return 13;
}
return 0;
}
int main(){
string s;
while(getline(cin, s)){
string s1 = s.substr(0, s.find('-')); //从-处截取成两段
string s2 = s.substr(s.find('-') + 1);
int space1 = 0, space2 = 0;
for(int i = 0; i < s1.length(); i++) //统计字符串中空格的数量
if(s1[i] == ' ')
space1++;
for(int i = 0; i < s2.length(); i++)
if(s2[i] == ' ')
space2++;
if(s1 == "joker JOKER" || s2 == "joker JOKER") //如果有王炸直接输出王炸
cout << "joker JOKER";
else if(space1 == 3 && space2 == 3){ //都有3个空格,说明4张牌,说明两个都是炸弹
if(getvalue(s1) > getvalue(s2)) //比较炸弹大小
cout << s1 << endl;
else
cout << s2 << endl;
}else if(space1 == 3) //字符串其中一个空格为3,说明一个是炸弹,输出炸弹
cout << s1 << endl;
else if(space2 == 3)
cout << s2 << endl;
else if(space1 == space2){ //没有炸弹的情况下相同类型才能比较
if(getvalue(s1) > getvalue(s2)) //个子、对子、三个、顺子都是比较第一个大小
cout << s1 << endl;
else
cout << s2 << endl;
}
else //无法比较
cout << "ERROR" << endl;
}
}
复杂度分析:
- 时间复杂度:,输入的字符串的长度为常数,需要遍历整个字符串,其中计算大小的时间也为
- 空间复杂度:,临时字符串长度也是常数
方法二:哈希表+长度比较法
具体做法:
可以用哈希表表示输入的单个字符,对应一个数字表示该字符即牌面的大小,如3对应最小1,2对应最大13,其中10因为是两个字符,我们可以用1来代替。于是哈希表中的key值就是牌面字符,value值就是其从1到13的大小关系。
首先读入的一行手牌根据“-”截取成两副手牌,然后遍历两副手牌,只将非0字符添加要比较的字符串中,0就需要,于是要比较的两个字符串与上面两个手牌应该是一致的,只是10变成了1.
然后查看要比较的两个字符串,如果任意一方有王炸,直接输出王炸即可。然后我们就看个子是一张牌,对子是两张牌一个空格,顺子是5张牌4个空格,三个是3张牌2个空格,炸弹是4张牌3个空格,很轻易发现不同类型的牌字符串长度不一样,那我们先查看两个字符串长度是否为7,就是是否有炸弹,如果都有炸弹,比较牌面后输出,否则输出有炸弹的一方。
对于剩余的类型,只有长度相等才能比较,否则不可以比较,比较的时候直接比较第一张牌的牌面值即可。
对于牌面值的比较我们可以根据字符进入哈希表中查找,然后比较其在哈希表中value的大小关系。
#include<bits/stdc++.h>
using namespace std;
//用哈希表记录每个字符相应的大小,其中10用字符1表示
unordered_map<char, int> nums{{'3', 1},{'4', 2}, {'5', 3}, {'6', 4}, {'7', 5},
{'8', 6}, {'9', 7}, {'1', 8},{'J', 9}, {'Q', 10}, {'K', 11}, {'A', 12}, {'2', 13}};
int main(){
string s;
while(getline(cin, s)){
string s1_origin = s.substr(0, s.find('-')); //从-处截取成两段
string s2_origin = s.substr(s.find('-') + 1);
string s1 = "", s2 = "";
for(int i = 0; i < s1_origin.length(); i++) //将原字符串中的10变成1
if(s1_origin[i] != '0')
s1 += s1_origin[i];
for(int i = 0; i < s2_origin.length(); i++) //将原字符串中的10变成1
if(s2_origin[i] != '0')
s2 += s2_origin[i];
if(s1 == "joker JOKER" || s2 == "joker JOKER") //如果有王炸直接输出王炸
cout << "joker JOKER";
else if(s1.length() == 7 && s2.length() == 7){ //字符串长度都为7,说明两个都是炸弹
if(nums[s1[0]] > nums[s2[0]]) //比较炸弹大小
cout << s1_origin << endl;
else
cout << s2_origin << endl;
}else if(s1.length() == 7) //字符串其中一个为7,说明一个是炸弹,输出炸弹
cout << s1_origin << endl;
else if(s2.length() == 7)
cout << s2_origin << endl;
else if(s1.length() == s2.length()){ //没有炸弹的情况下相同类型才能比较
if(nums[s1[0]] > nums[s2[0]]) //个子、对子、三个、顺子都是比较第一个大小
cout << s1_origin << endl;
else
cout << s2_origin << endl;
}
else //无法比较
cout << "ERROR" << endl;
}
}
复杂度分析:
- 时间复杂度:,输入的字符串的长度为常数,需要遍历整个字符串,其中哈希表查找的时间也为
- 空间复杂度:,哈希表的大小为常数空间,临时字符串长度也是常数