题目的主要信息:

  • 输入两手牌,两手牌之间用"-"连接,每手牌的每张牌以空格分隔,"-"两边没有空格
  • 比较两手牌大小,输出较大的牌,如果不存在比较关系则输出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;
    }
}

复杂度分析:

  • 时间复杂度:O(1)O(1),输入的字符串的长度为常数,需要遍历整个字符串,其中计算大小的时间也为O(1)O(1)
  • 空间复杂度:O(1)O(1),临时字符串长度也是常数

方法二:哈希表+长度比较法

具体做法:

可以用哈希表表示输入的单个字符,对应一个数字表示该字符即牌面的大小,如3对应最小1,2对应最大13,其中10因为是两个字符,我们可以用1来代替。于是哈希表中的key值就是牌面字符,value值就是其从1到13的大小关系。

首先读入的一行手牌根据“-”截取成两副手牌,然后遍历两副手牌,只将非0字符添加要比较的字符串中,0就需要,于是要比较的两个字符串与上面两个手牌应该是一致的,只是10变成了1.

然后查看要比较的两个字符串,如果任意一方有王炸,直接输出王炸即可。然后我们就看个子是一张牌,对子是两张牌一个空格,顺子是5张牌4个空格,三个是3张牌2个空格,炸弹是4张牌3个空格,很轻易发现不同类型的牌字符串长度不一样,那我们先查看两个字符串长度是否为7,就是是否有炸弹,如果都有炸弹,比较牌面后输出,否则输出有炸弹的一方。

对于剩余的类型,只有长度相等才能比较,否则不可以比较,比较的时候直接比较第一张牌的牌面值即可。

对于牌面值的比较我们可以根据字符进入哈希表中查找,然后比较其在哈希表中value的大小关系。

alt

#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;
    }
}

复杂度分析:

  • 时间复杂度:O(1)O(1),输入的字符串的长度为常数,需要遍历整个字符串,其中哈希表查找的时间也为O(1)O(1)
  • 空间复杂度:O(1)O(1),哈希表的大小为常数空间,临时字符串长度也是常数