题意
给出两个不同的斗地主中有效的牌组合,输出更大的那一组牌,如果无法比较,输出ERROR
方法
转态转换与实现
因为扑克牌描述上,2比3大,又有J,Q,K和大小王,如果把这些都写到 比较过程中,if的判断条件太过于复杂了
所以这里做了一个映射
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | J | Q | K | A | 2 | joker | JOKER |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
把它们映射到 0~14
的整数,这样它们的大小关系和原来保持一致,而可以减少大量的if
当我们把值变成数值后,接下来第二部分就是把牌列表转换成牌型,这里同样做一个映射,每次输出一个pair<类型,最小值>
炸弹 | 个子 | 对子 | 三个 | 顺子 |
---|---|---|---|---|
{-1,最小值} | {0,最小值} | {1,最小值} | {2,最小值} | {3/4/5/6...,最小值} |
这样映射以后,只用关注是否有-1,因为炸弹能和任何类型比较,剩余的就是类型是否相同,如果相同,比较最小值即可
上面两个映射都做成函数,剩下就是遍历和简单比较了
代码
#include<bits/stdc++.h>
using namespace std;
// 3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
int s2int(const char * s,int n){ // 字符串转值
if(n == 2)return 7; // 10
if(n == 5){
if(s[0] == 'j')return 13; // joker
else return 14; // JOKER
}
if(s[0] == '2')return 12;
if(s[0] == 'A')return 11;
if(s[0] == 'K')return 10;
if(s[0] == 'Q')return 9;
if(s[0] == 'J')return 8;
return s[0]-'3';
}
// 数组 转 类型 和 值
// 炸弹 个子 对子 三个 顺子
// -1 0 1 2 3,4,5,6
pair<int,int> a2tv(const vector<int>&arr){
if(arr.size() == 1)return {0,arr[0]}; // 个
if(arr.size() == 2){
if(arr[0] == arr[1])return {1,arr[0]}; // 对
else return {-1,arr[0]}; // 王炸
}
if(arr.size() == 3){
if(arr[0] == arr[1])return {2,arr[0]}; // 三
else return {3,arr[0]}; // 顺
}
if(arr.size() == 4){
if(arr[0] == arr[1]) return {-1,arr[0]}; // 炸
else return {4,arr[0]}; // 顺
}
return {arr.size(), arr[0]}; // 顺
}
int main() {
string s;
while(getline(cin,s)){
int n = s.length();
vector<int>arr[2] = {};
int itr = 0;
int dpos = 0; // - 的下标
for(int i = 0;i <= n;i++){
if(s[i] == ' ' || s[i] == '-' || s[i] == '\0'){ // 分割字符
arr[!!dpos].push_back(s2int(s.c_str()+itr,i-itr));
if(s[i] == '-') dpos = i;
itr = i+1;
}
}
s[dpos] = '\0';
auto ltv = a2tv(arr[0]);
auto rtv = a2tv(arr[1]);
if(ltv.first == rtv.first){ // 同类型
if(ltv.second < rtv.second){
printf("%s\n",s.c_str()+dpos+1);
}else{
printf("%s\n",s.c_str());
}
}else if(ltv.first == -1 || rtv.first == -1){ // 至少一个是炸弹
if(rtv.first == -1){
printf("%s\n",s.c_str()+dpos+1);
}else{
printf("%s\n",s.c_str());
}
}else{ // 非同类型无法比较
printf("ERROR\n");
}
}
return 0;
}
复杂度分析
时间复杂度: 所有的操作都是常数级别, 所以总复杂度为
空间复杂度: 存储字符串以外都是常数个数的额外变量,所以空间复杂度为
减少if,增加配置表,判断顺序优化
把牌转变成数字的过程用了很多if,如果转换成表会更加易读。
输出的部分,既然是if/else 加单条语句,就可以用三目运算简化
同时牌型计算如果把顺的逻辑判断提前,也可以减少if
代码
#include<bits/stdc++.h>
using namespace std;
// 3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
int s2int(const char * s,int n){ // 字符串转值
pair<char*,int> si[] = { // 字符串 和 值
{"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},
{"joker",13},
{"JOKER",14},
};
for(int i =0; i<15; i++){ // 因为前两个字符各不相等,只用比前两个
if(s[0] == si[i].first[0] && (n == 1?'\0':s[1]) == si[i].first[1] ){ // 超过长度的部分是 '\0'
return si[i].second;
}
}
assert(false);
return -1;
}
// 数组 转 类型 和 值
// 炸弹 个子 对子 三个 顺子
// -1 0 1 2 3,4,5,6
pair<int,int> a2tv(const vector<int>&arr){
if(arr.size() == 1)return {0,arr[0]}; // 个
if(arr.size() == 2){
if(arr[0] == arr[1])return {1,arr[0]}; // 对
else return {-1,arr[0]}; // 王炸
}
if(arr[0] < arr[1]) {
return {arr.size(), arr[0]}; // 顺
}
if(arr.size() == 3){
return {2,arr[0]}; // 三
}
if(arr.size() == 4){
return {-1,arr[0]}; // 炸
}
assert(false);
return {-1, -1};
}
int main() {
string s;
while(getline(cin,s)){
int n = s.length();
vector<int>arr[2] = {};
int itr = 0;
int dpos = 0; // - 的下标
for(int i = 0;i <= n;i++){
if(s[i] == ' ' || s[i] == '-' || s[i] == '\0'){ // 分割字符
arr[!!dpos].push_back(s2int(s.c_str()+itr,i-itr));
if(s[i] == '-') dpos = i;
itr = i+1;
}
}
s[dpos] = '\0';
auto ltv = a2tv(arr[0]);
auto rtv = a2tv(arr[1]);
if(ltv.first == rtv.first){ // 同类型
printf("%s\n",s.c_str()+(ltv.second < rtv.second?dpos+1:0));
}else if(ltv.first == -1 || rtv.first == -1){ // 至少一个是炸弹
printf("%s\n",s.c_str()+(rtv.first == -1?dpos+1:0));
}else{ // 非同类型无法比较
printf("ERROR\n");
}
}
return 0;
}
复杂度分析
时间复杂度: 所有的操作都是常数级别, 所以总复杂度为
空间复杂度: 存储字符串以外都是常数个数的额外变量,所以空间复杂度为