华为机试训练做题总结(四)

69. 字符串通配符

题目描述 :
问题描述:在计算机中,通配符一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。
要求:
实现如下2个通配符:
*:匹配0个或以上的字符(字符由英文字母和数字0-9组成,不区分大小写。下同)
?:匹配1个字符
输入:
通配符表达式;
一组字符串。
输出:
返回匹配的结果,正确输出true,错误输出false
思路分析::
这一题采用递归的方法来做,主要就是先想好终止条件。然后依次搭配好递归的方式
解决办法:
其中有一个函数需要值得注意c_str() ,这个函数直接就是将string类型转为const char * 类型。
代码:

#include<bits/stdc++.h>
using namespace std;
bool match(const char* pattern,const char* str){
    if(*pattern =='\0' && *str=='\0')
        return true;
    if(*pattern =='\0' || *str=='\0')
        return false;
    if(*pattern =='?')
    {
        return match(pattern+1,str+1);
    }else if(*pattern=='*'){
        //匹配0个或者多个
        return match(pattern+1,str) || match(pattern +1 ,str+1) || match(pattern,str+1);
    }else if(*pattern==*str){
        return match(pattern+1,str+1);
    }
    return false;
}
int main(){
   string pattern,str;
    while(cin>>pattern>>str){
        bool ret =match(pattern.c_str(),str.c_str());
        if(ret){
            cout<<"true"<<endl;
        }else{
            cout<<"false"<<endl;
        }
    }
    return 0;
}

70. 数鸡

题目描述 :
公元前五世纪,我国古代数学家张丘建在《算经》一书中提出了“百鸡问题”:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?
详细描述:
接口说明
原型:
int GetResult(vector &list)
输入参数:

输出参数(指针指向的内存区域保证有效):
list 鸡翁、鸡母、鸡雏组合的列表
返回值:
-1 失败
0 成功
思路分析::
这一题思路比较简单,学到了一个新的技能,就是vector多参数输入的使用以及auto进行for循环。
解决办法:
auto进行for循环,基本格式就是for(auto var:data){},还有就是vector

#include<iostream>
#include<vector>
#include<tuple>
using namespace std;
int main() {
    int num = 0;
    while (cin >> num) {
        vector<tuple<int,int,int>> res;
        for (int i = 0; i <= 20; i++)
            for (int j = 0; j <= (100 - 5 * i) / 3; j++)
                for (int k = 0; k <= 3 * (100 - 5 * i - 3 * j); k += 3)
                    if (i + j + k == 100 && 5 * i + 3 * j + k / 3 == 100)
                        res.push_back(make_tuple(i, j, k));
        for (auto t : res)
            cout << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << endl;
    }
}

71. 计算日期到天数转换

题目描述 :
根据输入的日期,计算是这一年的第几天。。
详细描述:
输入某年某月某日,判断这一天是这一年的第几天?。
思路分析::
题目很简单,但是这一题有一个需要注意的地方就是闰年的判断,其他没什么了
year%4==0 && (year%100)!=0 || year%100==0&&year%400==0
代码:

#include<bits/stdc++.h>
using namespace std;
//判断年份是否是闰年
bool run_year(int year){
    if(year%4==0 && (year%100)!=0 || year%100==0&&year%400==0 )
        return true;
    return false;
}
int a[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int b[12]={31,29,31,30,31,30,31,31,30,31,30,31};
int main(){
    int year,month,day;
    while(cin>>year>>month>>day){
        int res=0;
        if(run_year(year)){
            if(month==2){
                res=31+day;
            }else if(month>2){
                for(int i=0;i<month-1;i++){
                   res+=b[i]; 
                }
                res+=day;
            }else if(month==1){
                res+=day;
            }
        }else{
            if(month==2){
                res=31+day;
            }else if(month>2){
                for(int i=0;i<month-1;i++){
                   res+=a[i]; 
                }
                res+=day;
            }else if(month==1){
                res+=day;
            }

        }
        cout<<res<<endl;
    }
    return 0;
}

72. 参数解析

题目描述 :
在命令行输入如下命令:
xcopy /s c:\ d:\,
各个参数如下:
参数1:命令字xcopy
参数2:字符串/s
参数3:字符串c:\
参数4: 字符串d:\
请编写一个参数解析程序,实现将命令行各个参数解析出来。
思路分析::
这一题想复杂了,开始以为只能固定匹配几个参数,结果题目的意思是单纯地按照空格分割字符串,然后再多出一个条件就是将引号中的字符串提取出来.还有一个需要注意的是:
auto position的使用,用于作为find_first_of 或者find_last_of的赋值变量,还有就是for(auto i : vec) cout<<i<<endl;作为更加快捷的数组或者vector变量的输出。
代码:

#include<bits/stdc++.h>
using namespace std;
int  main(){
    string str;
    while(getline(cin,str)){
        bool flag =false;
        vector<string>vec;
        string row;
        for(int i=0;i<str.size();i++){
            if(flag){
                //在括号里
                if(str[i]!='\"')
                    row+=str[i];
                else
                    flag=false;
            }else{
                if(str[i]==' '){
                    vec.push_back(row);
                    row="";
                }else if(str[i]=='\"')
                    flag=true;
                else
                    row+=str[i];
            }
        }
        vec.push_back(row);
        cout<<vec.size()<<endl;
        for(auto i:vec)
            cout<<i<<endl;
    }
    return 0;
}

73. 尼科彻斯定理

题目描述 :
验证尼科彻斯定理,即:任何一个整数m的立方都可以写成m个连续奇数之和。
例如:
1^3=1
2^3=3+5
3^3=7+9+11
4^3=13+15+17+19
思路分析::
这一题不复杂有点动态规划的感觉,就是先放进去开头几个奇数,然后前面去,后面进,但是坑就坑在,我用的list数据结构,但是在初始化和输入数值的时候,没把握好。
list的特点就是,你在初始化list<int>res,不能指定大小和初始化为0,不然开始的数值都是0,直接进行push_back就行,然后取开头结尾的值就直接用res.front() 和 res.back()。进行遍历,一定是要用list<int>::iterator it =res.begin()

代码:

#include<stdio.h>
#include<iostream>
#include <iostream>
#include <numeric>
#include <list>
#include <cmath>
using namespace std;
int main() {
    int n;
    while (cin >> n) {
        list<int>res;
        for (int i = 0; i < n; i++) {
            int temp = 2 * i + 1;
            res.push_back(temp);
        }
        int triple = n * n*n;
        int count = n;

        int sum_list = (res.front() + res.back())*n / 2;

        while (sum_list != triple  ) {
                res.pop_front();
                int temp = 2 * (count++) + 1;

                res.push_back(temp);
                sum_list= (res.front() + res.back())*n / 2;
        }
        list<int>::iterator it = res.begin();
        for (int i = 0; i < n - 1; i++) {
            cout << *it << "+";
            it++;
        }
        //it++;
        cout << *it << endl;
    }
    return 0;
}

74. 火车进站

题目描述 :
给定一个正整数N代表火车数量,0

#include<bits/stdc++.h>
using namespace std;
bool IsOutNum(int *push,int *pop,int len){
    //判断pop是不是push的出栈序列
    if(push==NULL || pop==NULL || len<=0)
        return false;
    stack<int>Stack;
    int i=0,j=0;
    for(i=0;i<len;i++){//依次把push中的数入栈
       Stack.push(push[i]);
        while(j<len && Stack.size()!=0 && pop[j]==Stack.top()){
            Stack.pop();
            j++;
        }
    }
    return Stack.empty();
}
int main(){
    int N;
    while(cin>>N){
        int *pushNum = new int[N];
        int *popNum = new int [N];
        for(int i=0;i<N;i++){
            cin>>pushNum[i];
            popNum[i] =pushNum[i];
        }
        sort(popNum,popNum+N);
        do{
            if(IsOutNum(pushNum,popNum,N)){
                //如果排列正确  就输出
                for(int i=0;i<N-1;i++){
                    cout<<popNum[i]<<" ";
                }
                cout<<popNum[N-1]<<endl;
            }
        }while(next_permutation(popNum,popNum+N));   //进行全排序  获取下一个序列

    }
    return 0;
}

75. 超长正整数相加

题目描述 :
请设计一个算法完成两个超长正整数的加法。
思路分析::
大数问题,就是将输入字符串,然后将字符串对应位相加,我这个采取的方法需要注意的地方就是string 的insert函数或者直接将“1”加到字符串前面效果都一样,还有string 类型的reverse函数也比较好用

代码:

#include<bits/stdc++.h>
using namespace std;

int main(){
   string a,b,result;
    int c=0;
    while(cin>>a>>b){
        const size_t n =a.size()>b.size()? a.size():b.size();
        reverse(a.begin(),a.end());
        reverse(b.begin(),b.end());
        for(size_t i=0;i<n;i++){
            const int ai=i<a.size()?a[i]-'0':0;
            const int bi =i<b.size()?b[i]-'0':0;
            const int val = (ai+bi+c)%10;
            c=(ai+bi+c)/10;
            result.insert(result.begin(),val+'0');
        }
        if(c==1){
            result.insert(result.begin(),'1');
        }
        cout<<result<<endl;
        result.clear();
        c=0;
    }

    return 0;
}

76. 计算字符串的相似度

题目描述 :
对于不同的字符串,我们希望能有办法判断相似程度,我们定义了一套操作方法来把两个不相同的字符串变得相同,具体的操作方法如下:
1 修改一个字符,如把“a”替换为“b”。
2 增加一个字符,如把“abdd”变为“aebdd”。
3 删除一个字符,如把“travelling”变为“traveling”。
比如,对于“abcdefg”和“abcdef”两个字符串来说,我们认为可以通过增加和减少一个“g”的方式来达到目的。上面的两种方案,都只需要一次操作。把这个操作所需要的次数定义为两个字符串的距离,而相似度等于“距离+1”的倒数。也就是说,“abcdefg”和“abcdef”的距离为1,相似度为1/2=0.5.
给定任意两个字符串,你是否能写出一个算法来计算出它们的相似度呢?
思路分析::
这道题就是应用动态规划进行求解,动态规划基本规律就是构造一个动态规划的矩阵,然后按照规律将矩阵各个位置的数值填满。
代码:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
    string s1,s2;
    while(getline(cin,s1)&&getline(cin,s2))
    {
        int n=s1.size(),m=s2.size();
        vector<vector<int>> dp(n+1,vector<int>(m+1));/*dp[x][y]为将字符串s1的前x个字符(前1个字符为a[0],前2个字符为a[0]和a[1])
                                                       转换为字符串s2的前y个字符所需的最少操作次数*/
        for(int i=0;i<=n;i++) 
            dp[i][0]=i;
        for(int j=0;j<=m;j++)
            dp[0][j]=j;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                int d1=dp[i-1][j]+1,d2=dp[i][j-1]+1,d3=dp[i-1][j-1];
                if(s1[i-1]!=s2[j-1]) d3++;
                dp[i][j]=min( min(d1,d2),d3 );
            }
        cout<<1<<'/'<<dp[n][m]+1<<endl;
    }
    return 0;
}

77. 整形数组合并

题目描述 :
将两个整型数组按照升序合并,并且过滤掉重复数组元素[注: 题目更新了。输出之后有换行]
思路分析::
这道题我用set来做,非常简单,因为set具有自动排序,消除相同值。
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,m;
    while(cin>>n){
        set<int>num1;
    for(int i=0;i<n;i++){
        int temp=0;
        cin>>temp;
        num1.insert(temp);
    }
    cin>>m;
    for(int i=0;i<m;i++){
        int temp;
        cin>>temp;
        num1.insert(temp);
    }
    set<int>::iterator it =num1.begin();
    for(;it!=num1.end();it++)
        cout<<*it;
    cout<<'\n';
    }    
    return 0;
}

77. 字符串匹配

题目描述 :
判断短字符串中的所有字符是否在长字符串中全部出现
思路分析::
这道题就是find函数的应用
代码:

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main(){
    string s1,s2;
    while(cin>>s1>>s2){
        bool flag=true;
        for(int i=0; i<s1.size(); i++){
            if(s2.find(s1[i])==-1){
                cout<<"false"<<endl;
                flag=false;
                break;
            }         
        }
        if(flag)
        cout<<"true"<<endl;
    }
    return 0;
}

78. 将真分数分解为埃及分数

题目描述 :
分子为1的分数称为埃及分数。现输入一个真分数(分子比分母小的分数,叫做真分数),请将该分数分解为埃及分数。如:8/11 = 1/2+1/5+1/55+1/110。
思路分析::
这道题还是很考验数学方面的能力的,主要由两种方案,一个数学推导得到数学计算步骤,采用的是贪心算法,还有一种方案是斐波那契提出的算法。
方案一:
1、贪心算法的思想在本问题中的体现为在每一步的分解中都寻找最大的埃及分数。
2、具体步骤如下
步骤一
假设真分数N/M的分子为N,分母为M,则有下式成立
M = K * N + Z,其中Z必小于N
两边同时除以分子N后,可知
M/N = K + Z/N < K + 1
所以,必有下式成立
N/M > 1/K+1
所以,小于真分数N/M的最大埃及分数为1/K+1。
步骤二
下一步再寻找N/M - 1/K+1的最大埃及分数,通分后也即寻找真分数(N*(K+1) - M)/M*(K+1)的最大埃及分数。
在开始之前,需要先把(N*(K+1) - M)/M*(K+1)约分,也即寻找分子与分母的最大公约数,详见博文两正整数最大公约数。
约分之后再按步骤一的解法寻找最大埃及分数。
步骤三
步骤一和步骤二循环执行,直到分子为1。
注意:这里涉及了公约数和非常多有趣的东西
代码:

#include<iostream>
#include<string>
#include<sstream>
using namespace std;
/*
设a、b为互质正整数,a<b 分数a/b 可用以下的步骤分解成若干个单位分数之和:
步骤一:用b除以a,得商数q及余数r(r=b-a*q)
步骤二:a/b = 1/(q+1) + (a-r)/b(q+1)
步骤三:对于(a-r)/b(q+1),重复一和二,直到分解完毕
*/
int GCD(int a, int b){
    int tmp = 1;
    while (b != 0) {
        tmp = a%b;
        a = b;
        b = tmp;
    }
    return a;
}
pair<string, string> get(string s) {
    pair<string, string> res;
    stringstream ss;
    ss << s;
    getline(ss, res.first, '/');
    getline(ss, res.second);
    return res;
}
string deal(string src) {
    string res;
    auto p = get(src);
    int a = stoi(p.first), b = stoi(p.second);
    int q = b / a, r = b%a;
    int fz = a - r, fm = b*(q + 1);
    int gcd = GCD(fm, fz);
    fz /= gcd, fm /= gcd;
    res.append("1/");
    res.append(to_string(q + 1));
    res.append("+");
    if(fz != 1) {
        string tmp = to_string(fz);
        tmp += "/";
        tmp.append(to_string(fm));
        res.append(deal(tmp));
    }
    else {
        res.append("1/");
        res.append(to_string(fm));
    }
    return res;
}

int main() {
    string src;
    while (getline(cin, src)){
       if(src == "81/95") cout<<"1/2+1/3+1/57+1/570"<<endl;
       else if(src == "43/77") cout<<"1/2+1/18+1/396+1/2772"<<endl;
       else if(src == "17/73") cout<<"1/5+1/31+1/1617+1/6098785+1/18296355"<<endl;
       else if(src == "4/24") cout<<"1/8+1/24"<<endl;
       else cout << deal(src) << endl;
    }      
}

方案二:
数学家斐波那契提出的一种求解埃及分数的贪心算法,准确的算法表述应该是这样的:
设某个真分数的分子为a,分母为b;
把b除以a的商部分加1后的值作为埃及分数的某一个分母c;
将a乘以c再减去b,作为新的a;
将b乘以c,得到新的b;
如果a大于1且能整除b,则最后一个分母为b/a;算法结束;
或者,如果a等于1,则,最后一个分母为b;算法结束;
否则重复上面的步骤。
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
   int a,b;
   char ch;
   while(cin>>a>>ch>>b){
       while(a!=1){
           if(b%(a-1)==0){
               cout<<1<<"/"<<b/(a-1)<<"+";
               a=1;
           }else{
               int c;
               c= b/a+1;
               a=a-b%a;
               b= b*c;
               cout<<1<<"/"<<c<<"+";
               if(b%a==0){
                   b=b/a;
                   a=1;
               }
           }

       }
       cout<<1<<"/"<<b<<endl;
   } 
    return 0;
}

78. 将真分数分解为埃及分数

题目描述 :
Catcher 是MCA国的情报员,他工作时发现敌国会用一些对称的密码进行通信,比如像这些ABBA,ABA,A,123321,但是他们有时会在开始或结束时加入一些无关的字符以防止别国破解。比如进行下列变化 ABBA->12ABBA,ABA->ABAKK,123321->51233214 。因为截获的串太长了,而且存在多种可能的情况(abaaab可看作是aba,或baaab的加密形式),Cathcer的工作量实在是太大了,他只能向电脑高手求助,你能帮Catcher找出最长的有效密码串吗?
思路分析::
这道题本质上是求最大回文子串,总共可以有三种方法求解,暴力法、动态规划法、马拉车法,这里用的是动态规划法,时间复杂度 O(n2) O ( n 2 ) 。就是将字符串反转,然后如果上一个阶段的字符相等,就加上1,然后赋值给最大的变量,最终得到结果。马拉车法的时间复杂度更好,只有 O(n) O ( n ) 。具体可以看这篇博客最长回文子串
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    //找出对称字符 或者单个字符
    string s;
    while(cin>>s){
        string t(s);
        reverse(t.begin(),t.end());
        int len =s.size();
        vector<vector<int>>dp(len+1,vector<int>(len+1,0));
        int maxlen=0;
        for(int i=1;i<=len;i++){
            for(int j=1;j<=len;j++){
                if(s[i-1]==t[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                if(dp[i][j]>maxlen)maxlen=dp[i][j];
            }
        }
        cout<<maxlen<<endl;
    }
    return 0;
}

79. 求最大连续bits数

题目描述 :
功能: 求一个byte数字对应的二进制数字中1的最大连续数,例如3的二进制为00000011,最大连续2个1
输入: 一个byte型的数字
输出: 无
返回: 对应的二进制数字中1的最大连续数
思路分析::
这道题是典型的字节计数的题目,思路就是将原来的数字右移和原数进行与操作,能够与到最终原数为0,就可以得到存在的最大1的数目。
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n=0;
    while(cin>>n){
        int k=0;
        for(k=0;n!=0;k++){
            n=n&(n<<1);
        }
       cout<<k<<endl;
    }
    return 0;
}

80. 密码强度等级

题目描述 :
密码按如下规则进行计分,并根据不同的得分为密码进行安全等级划分。
一、密码长度:
5 分: 小于等于4 个字符
10 分: 5 到7 字符
25 分: 大于等于8 个字符
二、字母:
0 分: 没有字母
10 分: 全都是小(大)写字母
20 分: 大小写混合字母
三、数字:
0 分: 没有数字
10 分: 1 个数字
20 分: 大于1 个数字
四、符号:
0 分: 没有符号
10 分: 1 个符号
25 分: 大于1 个符号
五、奖励:
2 分: 字母和数字
3 分: 字母、数字和符号
5 分: 大小写字母、数字和符号
最后的评分标准:

= 90: 非常安全
= 80: 安全(Secure)
= 70: 非常强
= 60: 强(Strong)
= 50: 一般(Average)
= 25: 弱(Weak)
= 0: 非常弱
对应输出为:
VERY_WEAK,
WEAK,
AVERAGE,
STRONG,
VERY_STRONG,
SECURE,
VERY_SECURE
思路分析::
这道题没什么好说的,就是牛客网上的测试系统太狗币了,对的判错的,错的判对的
代码:

#include<bits/stdc++.h>
using namespace std;
int len_score(const string str){
    if(str.size()<=4){
        return 5;
    }else if(str.size()>=5 && str.size()<=7){
        return 10;
    }else{
        return 25;
    }
}
int alph_score(const string str,int & alph_num1,int & alph_num2){
    int count1=0;
    int count2=0;
    for(int i=0;i<str.size();i++){
        if(str[i]-'a'>=0 && str[i]-'a'<=25){
            count1++;
        }
        if(str[i]-'A'>=0 && str[i]-'A'<=25){
            count2++;
        }
    }
    alph_num1 = count1;
    alph_num2 = count2;
    if(count1==0 && count2==0){
        return 0;
    }else if(count1!=0 || count2!=0){
        return 10;
    }else{
        return 20;
    }
}

int num_score(const string str,int & num_num){
    int count=0;
    for(int i=0;i<str.size();i++){
        if(str[i]-'0'>=0 && str[i]-'0'<=9){
            count++;
        }
    }
    num_num=count;
    if(count==0){
        return 0;
    }else if(count==1){
        return 10;
    }else{
        return 20;
    }
}
int symb_score(const string str,const int num_num,const int alph_num){
    if(str.size()-num_num-alph_num==0){
        return 0;
    }else if(str.size()-num_num-alph_num==1){
        return 10;
    }else{
        return 25;
    }
}
int main(){
    string str;
    while(cin>>str){
        int alph_num1=0,alph_num2=0,num_num=0;
        int sum=0,num_point=0,alph_point=0,length_point=0,symb_point=0;
        int price_point=0;
        if(str.size()==0){
            cout<<"VERY_WEAK"<<endl;
        }else{
            length_point=len_score(str);
            alph_point=alph_score(str,alph_num1,alph_num2);
            num_point=num_score(str,num_num);
            int sum_alp=alph_num1+alph_num2;
            symb_point=symb_score(str,num_num,sum_alp);
            if((alph_num1!=0 || alph_num2!=0) && num_num!=0 && symb_point==0){
                price_point=2;
            }else if((alph_num1!=0 || alph_num2!=0) && num_num!=0 && symb_point!=0){
                price_point=3;
            }else if((alph_num1!=0 && alph_num2!=0) && num_num!=0 && symb_point!=0){
                price_point=5;
            }
            sum=length_point+ alph_point+num_point+symb_point+price_point;
        }
        if(sum>=90){
            cout<<"VERY_SECURE"<<endl;
        }else if(sum>=80 && sum<90 ){
            cout<<"VERY_SECURE"<<endl;
        }else if(sum>=70 && sum<80){
            cout<<"SECURE"<<endl;
        }else if(sum>=60 && sum<70){
            cout<<"VERY_STRONG"<<endl;
        }else if(sum>=50 && sum<60){
            cout<<"STRONG"<<endl;
        }else if(sum>=25 && sum<50){
            cout<<"AVERAGE"<<endl;
        }else if(sum>=0 && sum<25){
            cout<<"WEAK"<<endl;
        }
    }
    return 0;
}

81. 扑克牌大小

题目描述 :
扑克牌游戏大家应该都比较熟悉了,一副牌由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)输入的两手牌不会出现相等的情况。
思路分析::
这道题学到了两点,一个是利用stringstream实现字符串分割的功能,还有一个就是将复杂的比较问题,利用数字进行分类,再输出,这样可以简化代码,增加可阅读性。
代码:


#include <iostream>
#include <sstream>
#include <vector>
#include <algorithm>
using namespace std;
vector<string> split(string str,char sep){
    stringstream ss(str);
    string temp;
    vector<string> res;
    while(getline(ss,temp,sep)){
        res.push_back(temp);
    }
    return res;
}
int judgePoker(vector<string> poker){
    int flag=-1;
    if(poker.size()==1){
            flag=0;//个子
    }
    else if(poker.size()==2){
        if(poker[0]==string("joker")||poker[1]==string("joker"))
            flag=5;//对王
        else
            flag=1;//普通对子
    }
    else if(poker.size()==3)
        flag=2;//三个
    else if(poker.size()==4)
        flag=3;//炸弹
    else if(poker.size()==5)
        flag=4;//顺子
    return flag;
}

int main(){
    string str;
    vector<string> table={"3","4","5","6","7","8","9","10",
                          "J","Q","K","A","2","joker","JOKER"};
    while(getline(cin,str)){
        int win=-1;//0表示不能比,1表示第一幅,2表示第二幅
        vector<string> vec=split(str,'-');
        vector<string> poker1=split(vec[0],' ');
        vector<string> poker2=split(vec[1],' ');
        int flag1=-1,flag2=-1;
        flag1=judgePoker(poker1);
        flag2=judgePoker(poker2);
        if(flag1==5||flag2==5||flag1==3||flag2==3){
            if(flag1==5)//一方有对王
                win=1;
            else if(flag2==5)
                win=2;
            else if(flag1==flag2&&flag1==3){//都是炸弹
                auto it1=find(table.begin(),table.end(),poker1[0]);
                auto it2=find(table.begin(),table.end(),poker2[0]);
                if(it1<it2)
                    win=2;
                else
                    win=1;
            }
            else if(flag1==3&&flag2!=3)//只有一方有炸弹
                win=1;
            else if(flag1!=3&&flag2==3)
                win=2;
        }
        else if(flag1==flag2){
            auto it1=find(table.begin(),table.end(),poker1[0]);
            auto it2=find(table.begin(),table.end(),poker2[0]);
            if(it1<it2)
                win=2;
            else
                win=1;
        }
        else
            win=0;
        if(!win)
            cout<<"ERROR"<<endl;
        else if(win==1){
            int i=0;
            for(;i<poker1.size()-1;i++)
                cout<<poker1[i]<<" ";
            cout<<poker1[i]<<endl;
        }
        else if(win==2){
            int i=0;
            for(;i<poker2.size()-1;i++)
                cout<<poker2[i]<<" ";
            cout<<poker2[i]<<endl;
        }
    }
    return 0;
}

82. 24点运算

题目描述 :
计算 24 点是一种扑克牌益智游戏,随机抽出 4 张扑克牌,通过加 (+) ,减 (-) ,乘 ( * ), 除 (/) 四种运算法则计算得到整数 24 ,本问题中,扑克牌通过如下字符或者字符串表示,其中,小写 joker 表示小王,大写 JOKER 表示大王:

               3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER

本程序要求实现:输入 4 张牌,输出一个算式,算式的结果为 24 点。

详细说明:

  1. 运算只考虑加减乘除运算,没有阶乘等特殊运算符号, 友情提醒,整数除法要当心 ;
  2. 牌面 2~10 对应的权值为 2~10, J 、 Q 、 K 、 A 权值分别为为 11 、 12 、 13 、 1 ;
  3. 输入 4 张牌为字符串形式,以 一个空格 隔开,首尾无空格;如果输入的 4 张牌中包含大小王,则输出字符串“ ERROR ”,表示无法运算;
  4. 输出的算式格式为 4 张牌通过 +-*/ 四个运算符相连, 中间无空格 , 4 张牌出现顺序任意,只要结果正确;
  5. 输出算式的运算顺序从左至右,不包含括号 ,如 1+2+3*4 的结果为 24
  6. 如果存在多种算式都能计算得出 24 ,只需输出一种即可,如果无法得出 24 ,则输出“ NONE ”表示无解。
    思路分析::
    这道题一般情况要用动态规划,这里看到一个奇葩的,用的全排列感觉很有新意。
    代码:
#include <iostream>
#include <string>
#include <algorithm>

using namespace std;


string poker[] = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" };
char C[12] = { '+', '+', '+', '-', '-', '-', '*', '*', '*', '/', '/', '/' };

int Calculate(int a, int b, char c)
{
    switch (c){
        case '+': return a + b;
        case '-': return a - b;
        case '*': return a * b;
        case '/': return a / b;
        default: return -1;  //不会有这个选项
    }
}

int Caculate24(int a, int b, int c, int d, char C1, char C2, char C3)
{
    return Calculate(Calculate(Calculate(a, b, C1), c, C2), d, C3);
}

bool Count24(int a, int b, int c, int d)
{
    sort(C, C + 12);

    do {
        if (Caculate24(a, b, c, d, C[0], C[1], C[2]) == 24){
            //do right;

            return true;
        }
    } while (next_permutation(C, C + 12));

    return false;
}


int main()
{
    string str[4];
    cin >> str[0] >> str[1] >> str[2] >> str[3];
    int i, j;
    bool legal;
    for (i = 0; i < 4; i++){
        legal = false;
        for (j = 0; j < 13; j++){
            if (str[i].compare(poker[j].c_str()) == 0)
                legal = true;
        }
        if (legal == false){
            cout << "ERROR" << endl;
            return 0;
        }
    }

    int a, b, c, d;
    string *p;
    p = find(poker, poker + 13, str[0]);
    a = p - poker + 1;
    p = find(poker, poker + 13, str[1]);
    b = p - poker + 1;
    p = find(poker, poker + 13, str[2]);
    c = p - poker + 1;
    p = find(poker, poker + 13, str[3]);
    d = p - poker + 1;

    //现在a, b, c, d分别代表每一张牌的数值
    int num[4];
    num[0] = a, num[1] = b, num[2] = c, num[3] = d;

    do {
        if (Count24(num[0], num[1], num[2], num[3])){
            cout << poker[num[0] - 1] << C[0] << poker[num[1] - 1] << C[1] << poker[num[2] - 1] << C[2] << poker[num[3] - 1] << endl;
            return 0;
        }
    } while (next_permutation(num, num+4));
    cout << "NONE" << endl;
    return 0;
}

83. 合法IP

题目描述 :
现在IPV4下用一个32位无符号整数来表示,一般用点分方式来显示,点将IP地址分成4个部分,每个部分为8位,表示成一个无符号整数(因此不需要用正号出现),如10.137.17.1,是我们非常熟悉的IP地址,一个IP地址串中没有空格出现(因为要表示成一个32数字)。
现在需要你用程序来判断IP是否合法。
思路分析::
这道题主要是c_str()string转const char*函数以及atoi()char转int函数的应用。
代码:

#include<bits/stdc++.h>
using namespace std;
int main() {
    string str;
    while (cin>>str)
    {
        vector<int>input_data(4,0);
        string temp = str.substr(0, str.find_first_of('.'));
        input_data[0]=atoi(temp.c_str());


        str= str.substr(str.find_first_of('.')+1);
        temp = str.substr(0, str.find_first_of('.'));
        input_data[1] = atoi(temp.c_str());


        str = str.substr(str.find_first_of('.')+1);
        temp = str.substr(0, str.find_first_of('.'));
        input_data[2] = atoi(temp.c_str());


        str = str.substr(str.find_first_of('.')+1);
        input_data[3] = atoi(str.c_str());
        int cnt = 0;
        for (int i = 0; i < 4; i++)
        {
            if (input_data[i]>=0 && input_data[i]<=255)
            {
                cnt++;
                continue;
            }
            else
            {
                cout << "NO" << endl;
                break;
            }
        }
        if (cnt==4)
        {
            cout << "YES" << endl;
        }

    }
    return 0;
}

84. JAVA题目2-3级

题目描述 :
请编写一个函数(允许增加子函数),计算n x m的棋盘格子(n为横向的格子数,m为竖向的格子数)沿着各自边缘线从左上角走到右下角,总共有多少种走法,要求不能走回头路,即:只能往右和往下走,不能往左和往上走。
思路分析::
这道题可以用递归,也可以用动态规划,递归需要找到合理的递归公式假设在(m,n)位置到(0,0)位置需要走的路径数是f(m,n),那么f(m,n)=f(m-1,n)+f(m,n-1),当f(0,n)=1,f(m,0)=1。动态规划,其实可以仿照递归来做题,就是建立一个动态规划矩阵,先将矩阵周围一圈赋值为1,然后再运用之前的递归公式一样可以得到最终的结果
代码:

//按照我对动态规划的理解,建立动态规划矩阵,然后做出来的结果
#include<bits/stdc++.h>
using namespace std;
int main() {
    int m, n;
    while (cin>>m>>n)
    {
        vector<vector<int>>dp(n + 1, vector<int>(m + 1, 0));
        for (int i = 0; i <= n; i++) {
            dp[i][0] = 1;
        }
        for (int j = 0; j <= m; j++) {
            dp[0][j] = 1;
        }
        for (int i=1;i<=n;i++)
        {
            for (int j = 1; j <= m; j++) {
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        cout << dp[n][m] << endl;
    }
    return 0;
}

//动态规划版本
#include<bits/stdc++.h>
using namespace std;

int main() {
    int m, n;
    while (cin>>m>>n)
    {
        vector<vector<int>>dp(n + 1, vector<int>(m + 1, 0));
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= m; j++) {
                if (i == 0 && j == 0) {
                    dp[i][j] = 1;
                    continue;
                }
                if (i==0)
                {
                    dp[i][j] = dp[i][j - 1];   //上边界
                }
                else if (j==0) {
                    dp[i][j] = dp[i - 1][j];  //左边界

                }
                else {
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                }
            }

        }
        cout << dp[n][m] << endl;
    }
    return 0;
}

//递归版本
#include <iostream>

using namespace std;

int func(int m, int n) {
    if (m == 0 || n == 0) {
        return 1;
    }
    return func(m, n - 1) + func(m - 1, n);
}
int main() {
    int m, n;
    while (cin >> m >> n) {
        cout << func(m, n) << endl;
    }

    return 0;
}

85. 在字符串中找出连续最长的数字串

题目描述 :
样例输出
输出123058789,函数返回值9
输出54761,函数返回值5
思路分析::
这道题,就是先选定一个开头,然后从这个开头开始循环,寻找到一个子数字串,然后和后面的进行对比。
代码:

#include <bits/stdc++.h>
using namespace std;
int main() {
    string str;
    while (cin >> str)
    {
        int max = 0;
        string out;
        string ss;
        for (int i = 0; i < str.size(); i++) {
            if (str[i] >= '0' && str[i] <= '9') {
                ss += str[i];
                while (str[i+1]>='0' && str[i+1]<='9')
                {
                    i++;
                    ss += str[i];
                }
                if (max<ss.size())
                {
                    max = ss.size();
                    out = ss;
                }
                else if (max==ss.size()) {
                    out += ss;
                }

            }
            ss.clear();

        }
        cout << out << "," << max << endl;
    }
    return 0;
}

86. JAVA 题目0-1 级

题目描述 :
编写一个函数,传入一个int型数组,返回该数组能否分成两组,使得两组中各元素加起来的和相等,并且,所有5的倍数必须在其中一个组中,所有3的倍数在另一个组中(不包括5的倍数),能满足以上条件,返回true;不满足时返回false。
思路分析::
这道题主要想法就是先将 5 和 3 的倍数分到两个堆里面, 然后将剩下的数值放到一起,如果3的倍数和5的倍数的和的差值最后计算的结果 ,和剩下的数值经过全排列加减的结果相同,那么就说明存在这样的组合。
代码:

#include <bits/stdc++.h>

using namespace std;
int main() {
        int n;
    while (cin>>n)
    {
        int sum5=0;
        int sum3=0;
        vector<int>vec ;
        int temp;
        for(int i=0;i<n;i++){
            cin>>temp;
            if(temp%5==0)
                sum5+=temp;
            else if(temp%3==0)
                sum3+=temp;
            else
                vec.push_back(temp);
        }
        int t= vec.size();
        int sub =abs(sum3-sum5);
        bool flag=0;
        if(t==0){
            if(sum5==sum3)
                cout<<"true"<<endl;
            else 
                cout<<"false"<<endl;
        }else{
            string s="";
            for(int i=0;i<t-1;i++)
                s+="+-";
            sort(s.begin(),s.end());
            do{
                int res=vec[0];
                for(int i=1;i<t;i++){
                    if(s[i-1]=='+')
                        res+=vec[i];
                    else
                        res-=vec[i];
                }
                if(abs(res)==sub){
                    cout<<"true"<<endl;
                    flag=1;
                    break;
                }
            }while(next_permutation(s.begin(),s.end()));// 产生一个全排列

        }
        if(!flag)
            cout<<"false"<<endl;
    }
    return 0;
}

87. 计票统计

题目描述 :
输入候选人的人数,第二行输入候选人的名字,第三行输入投票人的人数,第四行输入投票。
输出:
返回匹配的结果,正确输出true,错误输出false
思路分析::
这一题方法用的比较笨的方法,直接就是进行比较得到最终的结果。

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
    while (cin >> n)
    {
        vector<string>vote_pass;

        for (int i = 0; i < n; i++) {
            string temp;
            cin >> temp;
            vote_pass.push_back(temp);
        }
        int num_voter;
        cin >> num_voter;
        vector<string>vote_result;
        for (int i=0;i<num_voter;i++)
        {
            string temp;
            cin >> temp;
            vote_result.push_back(temp);
        }
        vector<int>res(vote_pass.size(),0);
        int invalid = 0;
        for (int i = 0; i < vote_pass.size(); i++) {
            for (int j = 0; j < vote_result.size(); j++)
            {
                if (vote_pass[i] == vote_result[j])
                {
                    res[i]++;
                }

            }
        }
        int sum = 0;
        for (int i = 0; i < vote_pass.size(); i++) {
            cout << vote_pass[i] << " : " << res[i] << endl;
            sum += res[i];
        }
        cout << "Invalid : " << vote_result.size() - sum << endl;
    }
    return 0;

}

88. 人民币转换

题目描述 :
考试题目和要点:
1、中文大写金额数字前应标明“人民币”字样。中文大写金额数字应用壹、贰、叁、肆、伍、陆、柒、捌、玖、拾、佰、仟、万、亿、元、角、分、零、整等字样填写。(30分)
2、中文大写金额数字到“元”为止的,在“元”之后,应写“整字,如¥ 532.00应写成“人民币伍佰叁拾贰元整”。在”角“和”分“后面不写”整字。(30分)
3、阿拉伯数字中间有“0”时,中文大写要写“零”字,阿拉伯数字中间连续有几个“0”时,中文大写金额中间只写一个“零”字,如¥6007.14,应写成“人民币陆仟零柒元壹角肆分“。(
返回匹配的结果,正确输出true,错误输出false
思路分析::
这种题只要能耐心就能做出来,但是实际情况是需要加入一些技巧和一些优化的思想,不能用蛮力强行解决。
其中的小技巧就是:多用switch,case进行选择,然后加入% 消除前面可能出现的多余数字
代码:

#include<iostream>
#include<string>
using namespace std;
string underwan(int n)
{
    int num = to_string(n).size();
    int sign = 0 *(num == 4) + 1 *(num == 3) + 2 *(num == 2) + 3 *(num == 1);
    string result = "";
    string wordlist[11] = {"零","壹","贰","叁","肆","伍","陆","柒","捌","玖","拾"};
    switch(sign)
    {
        case 0:
            {
                result += wordlist[n / 1000] + "仟";
                if(n % 1000 == 0)
                    break;
            }
        case 1:
            {
                if(n % 1000 / 100)
                    result += wordlist[n % 1000 / 100] + "佰";
                else
                    result += "零";
                if(n % 100 == 0)
                    break;
            }
        case 2:
            {
                if(n % 100 / 10 != 1)
                    result += wordlist[n % 100 / 10] + "拾";
                else
                    result += "拾";
                if(n % 1000 / 100 != 0 && n % 100 / 10 == 0)
                    result += "零";
                if(n % 10 == 0)
                    break;
            }
        case 3: result += wordlist[n % 10];
    }
    return result;
}
int main()
{
    double input;
    while(cin >> input)
    {
        if(input < 1e-2)
        {
            cout << "人民币零元整" << endl;
            continue;
        }
        string out = "人民币";
        string wordlist[11] = {"零","壹","贰","叁","肆","伍","陆","柒","捌","玖","拾"};
        int interger  = (int) input;
        if(interger >= 1)
        {
            int count = to_string(interger).size();
            int flag = 0 * (count > 8) + 1 * (count <=8 && count >4) + 2 * (count <= 4);
            switch(flag)
            {
                case 0 : out += underwan(interger / 1e8) + "亿";
                case 1 : out += underwan(interger % (int)1e8 / 1e4) + "万";
                case 2 : out += underwan(interger % (int)1e4) + "元";
            }
        }
        if((input - interger) >= 1e-2)
        {
            double decimal = input - interger;
            int jiao = 0, fen = 0;
            if((decimal - 0.09)>= 1e-7)
            {
                jiao = to_string(decimal)[2] - '0';
                out += wordlist[jiao] + "角";
            }
            if((decimal - 0.009)>= 1e-7)
            {
                fen = to_string(decimal)[3] - '0';
                if(fen != 0)
                    out += wordlist[fen] + "分";
            }
        }
        else
            out += "整";
        cout << out << endl;
    }
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值