题目的主要信息:
- 输入两手牌,两手牌之间用"-"连接,每手牌的每张牌以空格分隔,"-"两边没有空格
- 比较两手牌大小,输出较大的牌,如果不存在比较关系则输出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<iostream>
#include<unordered_map>
#include<string>
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;
}
}
复杂度分析:
- 时间复杂度:,输入的字符串的长度为常数,需要遍历整个字符串,其中哈希表查找的时间也为
- 空间复杂度:,哈希表的大小为常数空间,临时字符串长度也是常数