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

26. 查找兄弟单词

题目描述 :

这里写图片描述

思路分析:
这一题我是服气的,一个是我自己的debug能力服气,一个是对华为OJ服气。真的职能用这两个词来形容。debug 一定要在vs里面自己编一遍,然后重新再找问题,其次就是可以利用cout<<”位置” 这样写法来判断哪个支路到底走没走、最后一个就是统计数目的时候一定要记得刷新的位置
华为OJ的判断我也是服气的,怎么做都是不对,莫名其妙的冒出一个小尾巴是什么鬼?

代码:

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

        string temp;
        string explor_str;
        for(int i=0;i<n;i++)
        {
            cin>>temp;
            str.push_back(temp);
        }
        cin>>explor_str;
        cin>>find_num;
        int counter=0;
        string bro_str;

        for(int i=0;i<str.size();i++){

            if(str[i]!=explor_str)
             {
                vector<int>stander(26,0);
                vector<int>explor(26,0);
                for(int j=0;j<str[i].length();j++){
                    stander[str[i][j]-'a']++;
                }
                for(int k=0;k<explor_str.length();k++){
                    explor[explor_str[k]-'a']++;
                }
                 if(stander==explor)
                {
                    counter++;
                    if(counter==find_num)
                    {   bro_str=str[i];
                    }
                }
            }
      }
        cout<<counter<<endl;
        for(int i=0;i<bro_str.size();i++)
        cout<<bro_str[i];
    }
    return 0;
}

27. 素数伴侣

题目描述 :
若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,它们能应用于通信加密。现在密码学会请你设计一个程序,从已有的N(N为偶数)个正整数中挑选出若干对组成“素数伴侣”,挑选方案多种多样,例如有4个正整数:2,5,6,13,如果将5和6分为一组中只能得到一组“素数伴侣”,而将2和5、6和13编组将得到两组“素数伴侣”,能组成“素数伴侣”最多的方案称为“最佳方案”,当然密码学会希望你寻找出“最佳方案”。
输入:
有一个正偶数N(N≤100),表示待挑选的自然数的个数。后面给出具体的数字,范围为[2,30000]。
输出:
输出一个整数K,表示你求得的“最佳方案”组成“素数伴侣”的对数。

思路分析:
这一题采用的是一般图的最大匹配算法,可以采用最大流或者匈牙利算法进行解决。但是通过分析可以知道这个题目里面只要偶数和质数相加就可以得到素数,然后这个题目就可以采用二分图的最大匹配算法进行解决。
二分图就是,你可以把图上的点分成2堆,每堆之内的点不会有边,2堆之间,才可能连边。换句话说,一条边,必定连2个来自不同堆的点。
现在,对每条边,一定连一个奇数,一个偶数,点能按奇数和偶数分成两部分,刚好就是二分图

进行二分图最大匹配的匈牙利算法基本思想:
首先将所有数字划分为奇数和偶数两类
对左边的点进行遍历,寻找右边与之匹配的点
1. 遇到右边点没有被匹配然后就采用贪心算法,将之匹配
2. 如果遇到右边点已经匹配,就将右边点的匹配点pre[x]进行重新匹配,寻找新的右边点,然后将这个右边点给原本的匹配点。

代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <vector>
using namespace std;

vector<int> G[105];

bool flag[105];
int pre[105];

bool dfs(int k){
    int x;
    for(int i=0;i<G[k].size();i++){
        x=G[k][i];
        if (flag[x]) continue;
        flag[x]=true;
        if((pre[x]==0)||dfs(pre[x])){
            pre[x]=k;
            return true;
        }
    }
    return false;
}

bool isprime[80000];
int nums[105];

int main(){
    memset(isprime,1,sizeof(isprime));
    isprime[0]=isprime[1]=false;
    for(int i=4;i<80000;i+=2)isprime[i]=false;
    for(int i=3;i*i<80000;i+=2)
        if(isprime[i]){
            for(int j=i*i;j<80000;j+=2*i) isprime[j]=false;
        }
    int n;
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++){
            scanf("%d",&nums[i]);
        }
        for(int i=1;i<=n;++i){
            for(int j=i+1;j<=n;++j){
                if(isprime[nums[i]+nums[j]]){
                    (nums[i]&1)?G[i].push_back(j):G[j].push_back(i);
                }
            }
        }

        memset(pre,0,sizeof(pre));
        int ans=0;
        for(int i=1;i<=n;i++){
            memset(flag,false,sizeof(flag));
            if (dfs(i)) ans++;
        }
        printf("%d\n",ans);

        for(int i=1;i<=n;++i){
            G[i].clear();
        }
    }
    return 0;
}

28. 字符串加解密

题目描述 :
1、对输入的字符串进行加解密,并输出。
2加密方法为:
当内容是英文字母时则用该英文字母的后一个字母替换,同时字母变换大小写,如字母a时则替换为B;字母Z时则替换为a;
当内容是数字时则把该数字加1,如0替换1,1替换2,9替换0;
其他字符不做变化。
3、解密方法为加密的逆过程。

接口描述:
实现接口,每个接口实现1个基本操作:
void Encrypt (char aucPassword[], char aucResult[]):在该函数中实现字符串加密并输出
说明:
1、字符串以\0结尾。
2、字符串最长100个字符。

int unEncrypt (char result[], char password[]):在该函数中实现字符串解密并输出
说明:
1、字符串以\0结尾。
2、字符串最长100个字符。

思路分析:
这一题常规思路吧,就是开始的时候我忘了加密和解密,然后导致了只能解决一个问题,后来把问题看清,问题解决了。但是后来又出现了问题,就是细节没把握好,一直没有debug出问题在哪儿。最终还是慢慢发现了问题的所在。要细致啊。
想试试查表法

代码:

#include<iostream>
#include<iomanip>
#include<string>
#include<vector>
using namespace std;
void Encrypt(string str){
    int len = str.size();
       for(int i=0;i<len;i++){
            if((str[i]-'a')>=0 && (str[i]-'a')<25){
                str[i]=str[i]-('a'-'A')+1;
            }else if((str[i]-'A')>=0 && (str[i]-'A')<25){
                str[i]=('a'-'A')+str[i]+1;
            }else if((str[i]-'0')>=0 && (str[i]-'0')<9){
                str[i]=str[i]+1;
            }else if(str[i]-'a'==25)
            {
                str[i]='A';
            }else if(str[i]-'A'==25){
                str[i]='a';
            }else if(str[i]=='9'){
                str[i]='0';
            }

        }
        cout<<str<<endl;
} 
int unEncrypt(string str){

  for(int i=0;i<str.length();i++){
            if((str[i]-'a')>0 && (str[i]-'a')<=25){
                str[i]=str[i]-('a'-'A')-1;
            }else if((str[i]-'A')>0 && (str[i]-'A')<=25){
                str[i]=('a'-'A')+str[i]-1;
            }else if((str[i]-'0')>0 && (str[i]-'0')<=9){
                str[i]=str[i]-1;
            }else if(str[i]-'a'==0)
            {
                str[i]='Z';
            }else if(str[i]-'A'==0){
                str[i]='z';
            }else if(str[i]=='0'){
                str[i]='9';
            }
        }
        cout<<str<<endl; 
        return 0;
}
int main(){

    string str1;
    string str2;
    while(getline(cin,str1))
    {
        getline(cin,str2);
        Encrypt(str1);
        unEncrypt(str2);
    }
    return 0;
}

29. 字符串合并处理

题目描述 :
按照指定规则对输入的字符串进行处理。
详细描述:
将输入的两个字符串合并。
对合并后的字符串进行排序,要求为:下标为奇数的字符和下标为偶数的字符分别从小到大排序。这里的下标意思是字符在字符串中的位置。
对排序后的字符串进行操作,如果字符为‘0’——‘9’或者‘A’——‘F’或者‘a’——‘f’,则对他们所代表的16进制的数进行BIT倒序的操作,并转换为相应的大写字符。如字符为‘4’,为0100b,则翻转后为0010b,也就是2。转换后的字符为‘2’; 如字符为‘7’,为0111b,则翻转后为1110b,也就是e。转换后的字符为大写‘E’。

举例:输入str1为”dec”,str2为”fab”,合并为“decfab”,分别对“dca”和“efb”进行排序,排序后为“abcedf”,转换后为“5D37BF”
接口设计及说明:
/*
功能:字符串处理
输入:两个字符串,需要异常处理
输出:合并处理后的字符串,具体要求参考文档
返回:无
*/
void ProcessString(char* str1,char str2,char strOutput)
{
}

思路分析:
这一题直接看的解析做的,让我没有想到的是string的处理可以这么的多样。
首先可以直接相加减,然后可以直接进行排序sort(s.begin(),s.end()),然后可以直接进行清空,最后寻找字符串中字符的位置用find()函数,找不到返回-1
最后总之查表大法好。

代码:

#include<bits/stdc++.h>
using namespace std;
const string helper1="0123456789abcdefABCDEF";
const string helper2="084C2A6E195D3B7F5D3B7F";
int main(){
    string str1;
    string str2;
    while(cin>>str1>>str2){
        string s,s1,s2;
        s=str1+str2;
        int len=s.size();
        for(int i=0;i<s.size();i++){
            if(i%2==0)
            {
                s1+=s[i];
            }else{
                s2+=s[i];
            }
        }
        sort(s1.begin(),s1.end());
        sort(s2.begin(),s2.end());
        s.clear();

        for(int i=0, j=0,k=0;i<len;i++){
            if(i%2==0){
                s+=s1[j++];
            }else{
                s+=s2[k++];
            }
        }
        for(int i=0;i<len;i++){
            if(helper1.find(s[i])!=-1)
            s[i]=helper2[helper1.find(s[i])];

        } 
        cout<<s<<endl; 
    }
    return 0;
}

30. 单词倒排

题目描述 :
对字符串中的所有单词进行倒排。
说明:
1、每个单词是以26个大写或小写英文字母构成;
2、非构成单词的字符均视为单词间隔符;
3、要求倒排后的单词间隔符以一个空格表示;如果原字符串中相邻单词间有多个间隔符时,倒排转换后也只允许出现一个空格间隔符;
4、每个单词最长20个字母;

思路分析:
这一题出现一个比较致命的错误,就是循环输入没有全部存入string里面,然后一个比较致命的是没有看清题意,而是直接认为只要是空格就可以。其中isalpha()函数起到非常重要的作用

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    string str;
    while(getline(cin,str)){
        vector<string>res;
        string temp;
        for(int i=0;i<str.length();i++){
            if(isalpha(str[i])){
                temp+=str[i];
            }else{
                if(!temp.empty()){
                res.push_back(temp);
                temp.clear();
                }
            }
        }
        if(!temp.empty()){
            res.push_back(temp);
        }
        for(int i=res.size()-1;i>=0;i--){
            cout<<res[i];
            if(i!=0){
                cout<<' ';
            }
        }
        cout<<endl;
        }
    return 0;
}

31. 字符串运用-密码截取

题目描述 :
Catcher是MCA国的情报员,他工作时发现敌国会用一些对称的密码进行通信,比如像这些ABBA,ABA,A,123321,但是他们有时会在开始或结束时加入一些无关的字符以防止别国破解。比如进行下列变化 ABBA->12ABBA,ABA->ABAKK,123321->51233214 。因为截获的串太长了,而且存在多种可能的情况(abaaab可看作是aba,或baaab的加密形式),Cathcer的工作量实在是太大了,他只能向电脑高手求助,你能帮Catcher找出最长的有效密码串吗?
思路分析:
这题本质上就是求字符串最长回文子串。比较好用的就是 Manacher 算法。时间复杂度 O(n) 。后来查阅了相关资料没看的太懂,然后在我的【算法知识总结】里记录了。

代码:

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int Manacher(string oriStr) {
    string newStr;
    int len = oriStr.size();
    for (int i = 0; i < len; i++) {//插入间隔符
        newStr += '#';
        newStr += oriStr[i];
    }
    newStr += '#';
    len = 2 * len + 1;             //新串长度,必为奇数
    int maxRight = 0;              //当前访问到的所有回文子串中,所能触及的最右一个字符的位置
    int pos = 0;                   //maxRight对应的回文子串对称轴的位置
    int*RL = new int[len];         //RL[i]记录以i为对称轴的最长回文子串半径长度(对称轴到最左或最右的距离)
    int maxLength = 0;             //记录最长回文子串长度
    for (int i = 0; i < len; i++) {
        if (i < maxRight) {        //分两种情况,i在maxRight左边和右边
            RL[i] = min(RL[2 * pos - i], maxRight - i);
        }
        else RL[i] = 1;
        while (i - RL[i]>=0 && RL[i] + i < len && newStr[i - RL[i]] == newStr[i + RL[i]])
            RL[i]++;               //以i为中心,在上步的基础上扩展,直至到达边界或左右字符不相等
        if (maxRight < RL[i] + i - 1) {//更新maxRight和pos
            maxRight = RL[i] + i - 1;
            pos = i;
        }
        maxLength = max(maxLength, RL[i] - 1);//对以i为中心的回文子串在原串总的长度即为RL[i] - 1
                                              //证明:新串中回文子串长度为2*RL[i]-1,其中RL[i]个
                                              //插入字符,则剩下的RL[i]-1个为原字符
    }
    return maxLength;
}

int main() {
    string str;
    while (cin >> str) {
        cout << Manacher(str) << endl;
    }
    return 0;
}

32. 整数与IP地址之间的转换

题目描述 :
原理:ip地址的每段可以看成是一个0-255的整数,把每段拆分成一个二进制形式组合起来,然后把这个二进制数转变成
一个长整数。
举例:一个ip地址为10.0.3.193
每段数字 相对应的二进制数
10 00001010
0 00000000
3 00000011
193 11000001
组合起来即为:00001010 00000000 00000011 11000001,转换为10进制数就是:167773121,即该IP地址转换后的数字就是它了。
的每段可以看成是一个0-255的整数,需要对IP地址进行校验
思路分析:
这题让我学到了位运算的相关知识。总之理解起来还是很饶的。不过还好,基本原理很简单。

  • IP地址: IP地址就是由四段十进制数组合得到的。每段数的范围是0-255(也就是 (201)(281) ,也就是IP地址每段都可以由八位二进制数表示。
  • 位操作: 位操作实际上就是一个将十进制看成是二进制的操作,a<<24 表示将a(注意:是无符号数)表示的二进制数左移了24位,同理>>
  • 十六进制数:十六进制用在这一题中有一个便利的地方就是 十六进制可以方便的表示为二进制,每四位就可以表示为一个十六进制数,比如:0xff0->1111 1111 0000 这其中我有一个低级错误就是忘记了0表示0000
    有了这些基本概念可以很方便地写出IP转十进制,十进制转IP的程序了
    代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
    unsigned int a,b,c,d;
    char ch;
    while(cin>>a>>ch>>b>>ch>>c>>ch>>d){
        cout<<((a<<24)|(b<<16)|(c<<8)|d)<<endl;
        cin>>a;
        cout<<((a& 0xff000000)>>24)<<"."<<((a& 0x00ff0000)>>16)<<"."<<((a& 0x0000ff00)>>8)<<"."<<((a& 0x000000ff))<<endl;
    }
    return 0;
}

33. 图片整理

题目描述 :
Lily上课时使用字母数字图片教小朋友们学习英语单词,每次都需要把这些图片按照大小(ASCII码值从小到大)排列收好。请大家给Lily帮忙,通过C语言解决。

思路分析:
这题我只想说一句查表大法好,基本思想就是通过在建立的表中找到对应的字符,然后在统计数组里面相应位置加1,这样就能统计出这个位置存在有多少个相应的字符了。
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    string str;
    const string helper="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    while(cin>>str){
        string res;
        vector<int>counter(62,0);
        for(int i=0;i<str.length();i++){
               counter[helper.find(str[i])]++; //关键所在
        }
        for(int i=0;i<counter.size();i++){
            for(int j=0;j<counter[i];j++){
                res+=helper[i];
            }
        }
        cout<<res<<endl;    
    }
    return 0;
}

34. 蛇形矩阵

题目描述 :
题目说明
蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。
样例输入
5
样例输出
1 3 6 10 15
2 5 9 14
4 8 13
7 12
11

思路分析:
这一题没有自己做出来,是看了别人怎么搞的,是我想多了,我想用小顶堆,结果大部分人还是在找规律。这不是我想的。

代码:

//这一题我的想法是建一个小顶堆,然后将之输出出来
//但是相关代码不会,只能选择其他的了
#include<bits/stdc++.h>
using namespace std;
int main(){
   int n;
    while(cin>>n){
        int beg=1;
        for(int i=1;i<=n;i++){
            cout<<beg;
            int temp=beg;
            for(int j=i+1;j<=n;j++){
                temp+=j;
                cout<<" "<<temp;
            }
            cout<<endl;
            beg+=i;
        }
    }
    return 0;
}

35. 字符串加密

题目描述 :
有一种技巧可以对数据进行加密,它使用一个单词作为它的密匙。下面是它的工作原理:首先,选择一个单词作为密匙,如TRAILBLAZERS。如果单词中包含有重复的字母,只保留第1个,其余几个丢弃。现在,修改过的那个单词属于字母表的下面,如下所示:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
T R A I L B Z E S C D F G H J K M N O P Q U V W X Y
上面其他用字母表中剩余的字母填充完整。在对信息进行加密时,信息中的每个字母被固定于顶上那行,并用下面那行的对应字母一一取代原文的字母(字母字符的大小写状态应该保留)。因此,使用这个密匙,Attack AT DAWN(黎明时攻击)就会被加密为Tpptad TP ITVH。
请实现下述接口,通过指定的密匙和明文得到密文。

思路分析:
这一题有一个比较坑的地方就是没有说明到底原文的字母是大写还是小写还是大写小写都有,所有一开始我用了大写就错了。然后OJ还提示我有没有循环输入处理多个case,我都懵逼了,while循环我明明写了啊。把我着急了一会儿,后来改了大小写就对了。
这个题思路上,我还是用的查表大法,先去重,然后判断哪些是出现了一次的字符然后依次输出,(当然我这次用了 string可以直接进行加减的概念),还有一个很重要的概念就是,如何将char类型的字符赋值给string字符串,利用:

string str="a";
str[0]=res[0];(其中res[0]是char类型的)

代码:

#include<bits/stdc++.h>
using namespace std;
string encrypt(string str){
    //去重
    string res="a";
    res[0]=str[0];
    int flag;
    for(int i=1;i<str.length();i++){
                flag=0;
        for(int j=0;j<res.length();j++){
            if(res[j]==str[i])
                flag=1;      
        }
        if(flag==1)
        {
           continue; 
        }else{
            res+=str[i];
        }
    }
    //加上26个字母中不在key中的字母 
    string temp=res;
    vector<int>counter(26,0);
    for(int i=0;i<res.size();i++){
        counter[res[i]-'a']++;
    }
    for(int i=0;i<26;i++){
        if(counter[i]==0)
        {
            res+=('a'+i);
        }
    }
    return res;
}
int main(){
    string key;
    string input_str;
    const string helper1="abcdefghijklmnopqrstuvwxyz";
    while(cin>>key){
        cin>>input_str;
        string helper2=encrypt(key);
        string res;
        for(int i=0;i<input_str.size();i++){
             res+=helper2[helper1.find(input_str[i])];
        }
        cout<<res<<endl;
    }
    return 0;
}

36. 统计每个月兔子的数量

题目描述 :
有一只兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子,假如兔子都不死,问每个月的兔子总数为多少?

思路分析:
这一题本质上是斐波那契数列,没什么好讲的,就是用递归来算,比较兴奋的是第一次写递归,有一些小错误,但是解决了,效果还不错,一颗赛艇

代码:

#include<bits/stdc++.h>
using namespace std;
int num_rabit(int month){
    int res;
    if(month==1 || month==2 )
            res=1;
    else
        res=num_rabit(month-1)+num_rabit(month-2);
    return res;
}
int main(){
    int month;
    while(cin>>month){

       int res=num_rabit(month);
        cout<<res<<endl;
    }
    return 0;
}

37. 求小球落地5次后的距离

题目描述 :
假设一个球从任意高度自由落下,每次落地后反跳回原高度的一半; 再落下, 求它在第5次落地时,共经历多少米?第5次反弹多高?

思路分析:
这一题溃败,思路上好多都是细节没把握好。需要细致啊。

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    double len;
    while(cin>>len){
        double sum=len;
        for(int i=1;i<5;i++)
        {
            len/=2.0;
            sum+=len*2.0; 
        }
        cout<<sum<<endl;
        cout<<len/2<<endl;
    }
    return 0;
}

38. 判断两个IP是否属于同一个子网

题目描述 :
子网掩码是用来判断任意两台计算机的IP地址是否属于同一子网络的根据。
子网掩码与IP地址结构相同,是32位二进制数,其中网络号部分全为“1”和主机号部分全为“0”。利用子网掩码可以判断两台主机是否中同一子网中。若两台主机的IP地址分别与它们的子网掩码相“与”后的结果相同,则说明这两台主机在同一子网中。
示例:
I P 地址  192.168.0.1
子网掩码  255.255.255.0
转化为二进制进行运算:
I P 地址 11010000.10101000.00000000.00000001
子网掩码 11111111.11111111.11111111.00000000
AND运算
    11000000.10101000.00000000.00000000
转化为十进制后为:
    192.168.0.0

I P 地址  192.168.0.254
子网掩码  255.255.255.0

转化为二进制进行运算:
I P 地址 11010000.10101000.00000000.11111110
子网掩码 11111111.11111111.11111111.00000000
AND运算
     11000000.10101000.00000000.00000000
转化为十进制后为:
     192.168.0.0
通过以上对两台计算机IP地址与子网掩码的AND运算后,我们可以看到它运算结果是一样的。均为192.168.0.0,所以这二台计算机可视为是同一子网络。

思路分析:
这一题主要就是将字符进行划分,之前有一道类似的题目 当时用的抖机灵的方法,其实真正用在了这道题上,并不是很实用。还是需要用遍历的方法进行求解。其中还有一个stoi的函数十分实用。还有一个就是这一题就是判断是否相等需要分为255和非255,这一点非常重要。

代码:

#include<bits/stdc++.h>
using namespace std;
vector<int>split(string s){
    vector<int>res;
    for(int i=0;i<s.length();i++){
        string temp;
        while(i<s.length() & s[i]!='.')
        {
            temp.push_back(s[i]);
            i++;
        }
        res.push_back(stoi(temp));

    }

    return res;
}

int main(){
    string mask;
    string ip1;
    string ip2;
    while(cin>>mask>>ip1>>ip2){
        vector<int>Mask=split(mask);
        vector<int>ipA=split(ip1);
        vector<int>ipB=split(ip2);
        bool flag=true;
        for(int i=0;flag && i<Mask.size();i++){
            if(Mask[i]==255){
                if(ipA[i]!=ipB[i]){
                    flag=false;
                    break;
                }

            }else{
                if(ipA[i] & Mask[i] != ipB[i] & Mask[i] ){
                    flag=false;
                    break;
                }
            }


        }
        if(flag){
            cout<<0<<endl;
        }else{
            cout<<2<<endl;
        }


    }

    return 0;
}

39. 输入一行字符,分别统计出包含英文字母、空格、数字和其它字符的个数。

题目描述 :
输入一行字符,分别统计出包含英文字母、空格、数字和其它字符的个数。
思路分析:
这一题思路上没什么问题,主要有一个是OJ的注意点,这一题不难,但是有一个地方屎坑,就是while(cin>>str){}进行输入会一个劲的报错,这是这个函数的问题,因为这类题目输入一堆字符串难免会进行拆分的,导致统计错误。因此只能采用while(getline(cin,str)){}进行输入,才正确。

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
   string str;
    while(getline(cin,str)){
        vector<int>counter(4,0);
        for(int i=0;i<str.length();i++){
            char cur=(char)str[i];
            if((cur>='a' && cur<='z') || (cur>='A' && cur<='Z') )
                counter[0]++;
            else if(cur==' ')
                counter[1]++;
            else if(cur<='9' && cur>='0')
                counter[2]++;
            else
                counter[3]++;
        }
        for(int i=0;i<counter.size();i++){
            cout<<counter[i]<<endl;
        }
    }


    return 0;
}

40. 称砝码

题目描述 :
现有一组砝码,重量互不相等,分别为m1,m2,m3…mn;
每种砝码对应的数量为x1,x2,x3…xn。现在要用这些砝码去称物体的重量,问能称出多少中不同的重量。
思路分析:
这一题是一道DP问题,主要就是用一个weights[j]=weights[j-1]+j*m[i]的公式,还有一个很重要的就是find(vector.begin(),vector.end(),w)==vector.end()
代表了其中不存在该值,全部都遍历过了。

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;// 砝码数
    int m[10]={0}; //每个砝码质量
    int x[10]={0};  //每个砝码数量
    while(cin>>n){
        for(int i=0;i<n;i++)
            cin>>m[i];
        for(int i=0;i<n;i++)
            cin>>x[i];
        vector<int>weights;   //存储的所有的砝码质量
        //将所有砝码称出的质量放入队列
        weights.push_back(0);
        for(int i=1;i<=x[0];i++){
            weights.push_back(i*m[0]);
        }
        for(int i=1;i<n;i++){
            int len=weights.size();
            for(int j=1;j<=x[i];j++){
                for(int k=0;k<len;k++){
                    int w=weights[k]+j*m[i];
                    if(find(weights.begin(),weights.end(),w)==weights.end())
                    {
                        weights.push_back(w);
                    }
                }
            }
        }
        cout<<weights.size()<<endl;
    }
    return 0; 
}

41. 学英语

题目描述 :
Jessi初学英语,为了快速读出一串数字,编写程序将数字转换成英文:
如22:twenty two,123:one hundred and twenty three。

说明:
数字为正整数,长度不超过九位,不考虑小数,转化结果为英文小写;
输出格式为twenty two;
非法数据请返回“error”;
关键字提示:and,billion,million,thousand,hundred。

方法原型:public static String parse(long num)
思路分析:
这一题基本都过了,最后OJ说我格式不对,不知道哪儿不对。然后一个问题就是好多地方考虑 的不够细致,改进了好多遍,希望下次能够认真仔细一点。其实这一题就是写一个函数然后主函数负责将数字划分为三部分就行了。思路上不是很难。

代码:



#include<bits/stdc++.h>
using namespace std;
const string helper1[5]={"and","billion","million","thousand","hundred"};
const string helper2[8]={"twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"};
const string helper3[10]={"zero","one","two","three","four","five","six","seven","eight","nine"};
const string helper4[10]={"ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"};
string thrible_num(long n){
        string res;
    vector<int>point_num;
    vector<int>temp;
    while (n) {
          temp.push_back(n % 10);
          n /= 10;
    }
    for (int i = 0; i < temp.size() ; i++) {
        int temp1 = temp[i];
        point_num.push_back(temp1);
    }

    int len = point_num.size();
    if (len == 1) {
        res += helper3[point_num[0]];
    }
    else if (len == 2) {
        if (point_num[0] == 1)
        {
            res += helper4[point_num[1]];
        }
        else
        {


                res += helper2[point_num[1] - 2];
                res += " ";
                if(point_num[0]!=0)
                res += helper3[point_num[0]];


        }
    }
    else if (len == 3) {

            res += helper3[point_num[2]];
            res += " ";

        if (point_num[1] == 1)
        {
            res += helper1[4];
            res +=" ";
            res+="and";
            res+=" ";
            res += helper4[point_num[0]];
        }
        else if(point_num[1] >1)
        {

                res += helper1[4];
                res +=" ";
                res+="and";
                res+=" ";
                res += helper2[point_num[1] - 2];
                res += " ";
                if(point_num[0]!=0)
                res += helper3[point_num[0]];

        }else if(point_num[1] == 0){
                res += helper1[4];
                res +=" ";
                res+="and";
                res+=" ";
                res += helper3[point_num[0]];
        }
    }
    return res;
}

int main(){
    long int n;
    while(cin>>n){
        string res;
     if(n<1000){
         res=thrible_num(n);
     }else if(n>=1000 && n<1000000){
         int temp=n/1000;
         n=n%1000;
         string str;
         res=thrible_num(temp);
         str=thrible_num(n);
         res+=" ";
         res+="thousand";
         res+=" ";
         res+=str;
     }else if(n>=1000000 && n<1000000000){
         int temp=n/1000000;
         n=n%1000000;
         string str;
         res=thrible_num(temp);
         res+=" ";
         res+="million";
         res+=" ";
         temp=n/1000;
         str=thrible_num(temp);
         res+=str;
         res+=" ";
         res+="thousand";
         res+=" ";
         n=n%1000;
         str=thrible_num(n);
         res+=str;

     }
     while (res[res.size() - 1] == ' ') res.erase(res.end() - 1);
     cout<<res<<endl;
    }
    return 0;
}

42. 迷宫问题

题目描述 :
定义一个二维数组N*M(其中2<=N<=10;2<=M<=10),如5 × 5数组下所示:

int maze[5][5] = {

    0, 1, 0, 0, 0,

    0, 1, 0, 1, 0,

    0, 0, 0, 0, 0,

    0, 1, 1, 1, 0,

    0, 0, 0, 1, 0,

};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。入口点为[0,0],既第一空格是可以走的路。
Input
一个N × M的二维数组,表示一个迷宫。数据保证有唯一解,不考虑有多解的情况,即迷宫只有一条通道。
思路分析:
这一题开始想的用DP,然后无情被打脸,其实这一题和之前的旅行商问题和背包问题都是采用的回溯法,主要的思想我写在了【算法知识总结】回溯法 这篇博客里面了。
注意:
其中vector设置的二维矩阵在数据的存取上有一些新的知识,非常厉害
1. 二维vector矩阵push_back({i,j})
2. 二维vector矩阵遍历输入

 for (auto &i : maze)
            for (auto &j : i)
                cin >> j;

.
3. 二维vector矩阵初始化

maze=vector<vector<int>>(N,vector<int>(M,0))

代码:

#include<iostream>
#include<vector>
using namespace std;

int N, M; //分别代表行和列
vector<vector<int>> maze;//迷宫矩阵
vector<vector<int>> path_temp;//存储当前路径,第一维表示位置
vector<vector<int>> path_best;//存储最佳路径

void MazeTrack(int i, int j)
{
    maze[i][j] = 1;//表示当前节点已走,不可再走
    path_temp.push_back({ i, j });//将当前节点加入到路径中

    if (i == N - 1 && j == M - 1) //判断是否到达终点
        if (path_best.empty() || path_temp.size() < path_best.size())
            path_best = path_temp;

    if (i - 1 >= 0 && maze[i - 1][j] == 0)//探索向上走是否可行
        MazeTrack(i - 1, j);
    if (i + 1 < N && maze[i + 1][j] == 0)//探索向下走是否可行
        MazeTrack(i + 1, j);
    if (j - 1 >= 0 && maze[i][j - 1] == 0)//探索向左走是否可行
        MazeTrack(i, j - 1);
    if (j + 1 < M && maze[i][j + 1] == 0)//探索向右走是否可行
        MazeTrack(i, j + 1);
    maze[i][j] = 0;         //恢复现场,设为未走
    path_temp.pop_back();
}
int main()
{
    while (cin >> N >> M)
    {
        maze = vector<vector<int>>(N, vector<int>(M, 0));
        path_temp.clear();
        path_best.clear();
        for (auto &i : maze)
            for (auto &j : i)
                cin >> j;
        MazeTrack(0, 0);//回溯寻找迷宫最短通路
        for (auto i : path_best)
            cout << '(' << i[0] << ',' << i[1] << ')' << endl;//输出通路
    }
    return 0;
}

43 . sudoku

题目描述 :
问题描述:数独(Sudoku)是一款大众喜爱的数字逻辑游戏。玩家需要根据9X9盘面上的已知数字,推算出所有剩余空格的数字,并且满足每一行、每一列、每一个粗线宫内的数字均含1-9,并且不重复。
输入:
包含已知数字的9X9盘面数组[空缺位以数字0表示]
输出:
完整的9X9盘面数组
思路分析:
这一题看的别人的写法采用的是DFS深度优先搜索。
代码:

#include <iostream> 
using namespace std;  
bool sign = false;   
int num[9][9]; 
void Output()
{  
    for (int i = 0; i < 9; i++){
        for (int j = 0; j < 8; j++)
            cout << num[i][j] << " ";
        cout << num[i][8];
        cout << endl;
    }
}

/* 判断key填入n格时是否满足条件,n代表第几个格子 */
bool Check(int n, int key)
{
    /* 判断n所在横列是否合法 */
    for (int i = 0; i < 9; i++){
        /* j为n竖坐标 */
        int j = n / 9;
        if (num[j][i] == key)
            return false;
    }

    /* 判断n所在竖列是否合法 */
    for (int i = 0; i < 9; i++){
        /* j为n横坐标 */
        int j = n % 9;
        if (num[i][j] == key)
            return false;
    }

    int y = n / 9 / 3 * 3;
    int x = n % 9 / 3 * 3;    
    /* 判断n所在的小九宫格是否合法 */
    for (int i = y; i < y + 3; i++) 
        for (int j = x; j < x + 3; j++)
            if (num[i][j] == key)
                return false;

    return true;
}

/* 深搜 */
int DFS(int n)
{
    /* 所有的都符合,退出搜索,n代表格子数,共81个格子,0~80 */
    if (n > 80){
        sign = true;
        return 0;
    }

    if (num[n / 9][n % 9] != 0)
        DFS(n + 1); 
    else{
        /* 否则对当前位一次填入1~9进行测试 */
        for (int i = 1; i <= 9; i++){
            if (Check(n, i)){
                num[n / 9][n % 9] = i;
                /* 继续搜索,后续位也填1~9测试,直到最后一位,通过的话置true */
                DFS(n + 1);
                /* 返回时如果构造成功,则直接退出 */
                if (sign) 
                    return 0;
                /* 如果构造不成功,还原当前位 */
                num[n/9][n%9] = 0;
            }

        }
    }
    return 0;
}

int main()
{ 
    for (int i = 0; i < 9; i++){
        for (int j = 0; j < 9; j++)
            cin >> num[i][j];
    }
    DFS(0);     //从第0格开始填
    Output();
}

44 . 名字的漂亮度

题目描述 :
给出一个名字,该名字有26个字符串组成,定义这个字符串的“漂亮度”是其所有字母“漂亮度”的总和。
每个字母都有一个“漂亮度”,范围在1到26之间。没有任何两个字母拥有相同的“漂亮度”。字母忽略大小写。
给出多个名字,计算每个名字最大可能的“漂亮度”。
思路分析:
这一题本质上是一个字符数字的统计以及排序的问题。
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    while(cin>>n){
        while(n--){
            string temp;  
            int k=26;
            int res=0;
            cin>>temp;
             vector<int>counter(26,0);
            for(int j=0;j<temp.length();j++){
                if(temp[j]>='a' && temp[j]<='z' )
                    counter[temp[j]-'a']++;
                else 
                    counter[temp[j]-'A']++;
            }

            sort(counter.begin(),counter.end());
            for(int i=counter.size()-1;i>=0;i--){
                res+=counter[i]*(k--);
            }
                cout<<res<<endl;
        }
    }
    return 0;
}

45 . 按字节截取字符串

题目描述 :
编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串。但是要保证汉字不被截半个,如”我ABC”4,应该截为”我AB”,输入”我ABC汉DEF”6,应该输出为”我ABC”而不是”我ABC+汉的半个”。
思路分析:
这一题开始没多想,就是直接一个如果存在字母常规的添加到输出字符串里面,如果存在汉字就多进一个。后来看了别人的看法,感觉也挺有的价值的。但是按照上面的做法没有考察到任何知识点,所以先无视string的这个功能。
汉字占两个字节,每个字节的ASCII码最高位均为1,由于char默认为带符号类型,所以汉字的ASCII码小于0,而英文数字等其他字符占一个字节,ASCII码最高位为0,值在0~127之间。因此,只需要判断该字节是否小于0就能推断出是否为半个汉字。再向前推算有连续几个半个汉字,若有偶数个,则输出最后半个汉字,否则不输出。
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    string str;
    int n;
    while(cin>>str){
        cin>>n;
        string res;
        for(int i=0;i<n;i++){
            if(str[i]>='a' && str[i]<='z' || str[i]>='A' && str[i]<='Z' )
            {
                res+=str[i];
            }else{
                i++;
                res+=str[i];
            }
        }
        cout<<res<<endl;
    }
    return 0;
}

46 . 线性插值

题目描述 :
信号测量的结果包括测量编号和测量值。存在信号测量结果丢弃及测量结果重复的情况。1.测量编号不连续的情况,认为是测量结果丢弃。对应测量结果丢弃的情况,需要进行插值操作以更准确的评估信号。采用简化的一阶插值方法,由丢失的测量结果两头的测量值算出两者中间的丢失值。假设第M个测量结果的测量值为A,第N个测量结果的测量值为B。则需要进行(N-M-1)个测量结果的插值处理。进行一阶线性插值估计的第N+i个测量结果的测量值为A+( (B-A)/(N-M) )*i (注:N的编号比M大。)
例如:只有测量编号为4的测量结果和测量编号为7的测量结果,测量值分别为4和10则需要补充测量编号为5和6的测量结果。其中测量编号为5的测量值=4 + ((10-4)/(7-4))*1 = 6。其中测量编号为6的测量值=4 + ((10-4)/(7-4))*2 = 8 2.测量编号相同,则认为测量结果重复,需要对丢弃后来出现的测量结果。
思路分析:
这一题开始没看懂 啥是舍弃 啥又是插值,其实插值是比较简单,但是这个思路理顺不太好整。其中题目给出的例子中有一个m值是没有用的。因此还被懵逼了。然后讲回正题,其中,第二行输入的两个值就是起初的基准值,然后将两个值分别代表标号以及主值,然后下一个标号还是一样的就舍弃即continue,如果不一样就将之与之前那一行的编号对比,如果中间差几个值,就需要进行插值。
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,m;
    while(cin>>n>>m){
        int M,N,A,B;
        cin>>M>>A;
        cout<<M<<" "<<A<<endl;
        for(int i=1;i<n;i++){
            cin>>N>>B;
            if(N==M)
                continue;
            else
            {
                for(int j=1;j<N-M;j++){
                    cout<<M+j<<" "<<A+(B-A)/(N-M)*j<<endl;
                }
                cout<<N<<" "<<B<<endl;
                M=N;
                A=B;
            }
        }

    }
    return 0;
}

47 . 从单向链表中删除指定值节点

题目描述 :
输入一个单向链表和一个节点的值,从单向链表中删除等于该值的节点,删除后如果链表中无节点则返回空指针。
链表结点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};

详细描述:

本题为考察链表的插入和删除知识。

链表的值不能重复

构造过程,例如

1 -> 2

3 -> 2

5 -> 1

4 -> 5

7 -> 2
最后的链表的顺序为 2 7 3 1 5 4
删除 结点 2
则结果为 7 3 1 5 4
思路分析:
这一题是考察基本功的,但是还是不太会,很伤。说明还需要多练习。
代码:

#include<bits/stdc++.h>
using namespace std;
struct ListNode{
    int key;
    ListNode* next;
    ListNode(int x):key(x),next(NULL){}
};
int main(){
    int n;
    int key,pre;
    while(cin>>n>>key){
        ListNode* head=new ListNode(key);
        n--;
        while(n--){
            cin>>key>>pre;
            ListNode* p=head;
            while(p->key != pre){
                p=p->next;
        }
            ListNode* curr=new ListNode(key);
            curr->next=p->next;
            p->next=curr;
        }
        cin>>key;
        ListNode* p=head;
        while(p){
            if(p->key !=key )
                cout<<p->key<<" ";
            p=p->next;
        }
        cout<<endl;
    }
    return 0;
}

48 . 多线程

题目描述 :
问题描述:有4个线程和1个公共的字符数组。线程1的功能就是向数组输出A,线程2的功能就是向字符输出B,线程3的功能就是向数组输出C,线程4的功能就是向数组输出D。要求按顺序向数组赋值ABCDABCDABCD,ABCD的个数由线程函数1的参数指定。
思路分析:
这一题是考察多线程,但是我这个投机取巧的,没啥用,还需要多学习啊。
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    while(cin>>n){
        string str="ABCD";
        for(int i=1;i<n;i++)
        {
            str=str+"ABCD";
        }
        cout<<str<<endl;
    }
    return 0;
}

49 . 四则运算

题目描述 :
输入一个string类型的字符串,里面是一条四则运算字符串,然后得到计算结果
思路分析:
这一题采用python进行计算就是一两行代码的问题,但是这一题实际考察的是,递归下降算法的使用,其实这类题目(当然包括括号的匹配问题)都是一个堆栈问题,通过堆栈的压栈和弹出,进行匹配计算的。
代码:

#include<bits/stdc++.h>
using namespace std;
void addNum(deque<string>& Q,int num){
    if(!Q.empty()){
        int cur=0;
        if(Q.back()=="*" || Q.back()=="/"){
            string top=Q.back();
            Q.pop_back();
            stringstream ss(Q.back());
            ss>>cur;
            Q.pop_back();
            num=top=="*"?(cur*num):(cur/num);
        } 
    }
    stringstream ss;
    ss<<num;
    Q.push_back(ss.str());
}
int getNum(deque<string>& Q){
    int num=0,R=0;
    string f("+");
    while(!Q.empty()){
        stringstream ss(Q.front());
        ss>>num;
        Q.pop_front();
        R=(f=="+")?(R+num):(R-num);
        if(!Q.empty()){
            f=Q.front();
            Q.pop_front();
        }
    }
    return R;
}
int* value(string & s,int i){
    deque<string>Q;
    int pre=0;
    while(i<s.length() && s[i]!=')' && s[i]!=']' && s[i]!='}'){
        if(s[i]>='0' && s[i]<='9'){
            pre=pre*10+s[i++]-'0';
        }else if(s[i]!='(' && s[i]!='[' && s[i]!='{'){
            addNum(Q,pre);
            string ss;
            ss+=s[i++];
            Q.push_back(ss);
            pre=0;

        }else{
            int * bra=NULL;
            bra=value(s,i+1);
            pre=bra[0];
            i=bra[1]+1;
        }
    }
    addNum(Q,pre);
    int *R=new int[2];
    R[0]=getNum(Q);
    R[1]=i;
    return R;
}
int main(){
    string s;
    while(cin>>s){
        int *R=value(s,0);
        cout<<R[0]<<endl;
    }
    return 0;
}

50 . 输出单向链表中倒数第k个节点

题目描述 :
输入说明
1 输入链表结点个数
2 输入链表的值
3 输入k的值
思路分析:
这一题是一个基础考察结果我还是不怎么熟,感觉很沮丧。还是多练练吧 其实链表真的还是比较基础的问题。而且很实用。多练习。
代码:

#include<bits/stdc++.h>
using namespace std;
struct ListNode{
    int key;
    ListNode * next;
    ListNode(int n):key(n),next(NULL){}
};
int main(){
    int n;
    while(cin>>n){
        int val;
        cin>>val;
        ListNode* head=new ListNode(val);
        ListNode* p=head;
        for(int i=1;i<n;i++){
            cin>>val;
            ListNode* q=new ListNode(val);
            p->next=q;
            p=p->next;
        }
        cin>>val;
        p=head;
        if(val==0){
            cout<<"0"<<endl;
        }else if((n-val)>=0){
            for(int i=1;i<=(n-val);i++){
                p=p->next;
            }
            cout<<p->key<<endl;

        }else{

            cout<<"NULL"<<endl;
        }


    }
    return 0;
}

51 . 计算字符串的距离

题目描述 :
Levenshtein 距离,又称编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。编辑距离的算法是首先由俄国科学家Levenshtein提出的,故又叫Levenshtein Distance。
Ex:
字符串A:abcdefg
字符串B: abcdef
通过增加或是删掉字符”g”的方式达到目的。这两种方案都需要一次操作。把这个操作所需要的次数定义为两个字符串的距离。
要求:
给定任意两个字符串,写出一个算法计算它们的编辑距离。
思路分析:
这一题是一道动态规划的题目,动态规划一般应用在最优子串的问题上,这一道题目也是这样。
AiA(a1,a2,a3,...am)ia1,a2,a3...ai
BjB(b1,b2,b3,...bn)jb1,b2,b3...bj
D(i,j)使AiBj
1. ai==bjD(i,j)=D(i1,j1)
2. ai!=bj

  • 若将它们修改为相等,则对两个字符串至少还要操作 D(i1,j1)
  • 若删除 aibjaiD(i1,j)
  • bjaibjD(i,j1)

此时 D(i,j)=min(D(i1,j1),D(i1,j),D(i,j1))+1
显然, D(i,0)=iD(0,j)=j, 再利用上述的递推公式 D(i,j)

其中使用vector建立二维数组的语法:

vector<vector<int>>dp(s1.size()+1,vector<int>(s2.size()+1,0));

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    string s1,s2;
    while(cin>>s1>>s2){
        vector<vector<int>>dp(s1.size()+1,vector<int>(s2.size()+1,0));
        for(int i=1;i<=s2.length();i++){
            dp[0][i]=i;
        }
        for(int i=1;i<=s1.length();i++){
            dp[i][0]=i;
        }
        for(int i=1;i<=s1.length();i++){
            for(int j=1;j<=s2.length();j++){
                int min1=min(dp[i-1][j],dp[i][j-1])+1;
                dp[i][j]=min((s1[i-1]==s2[j-1]?0:1)+dp[i-1][j-1],min1);
            }

        }
        cout<<dp[s1.size()][s2.size()]<<endl;
    }
    return 0;
}

52 . 杨辉三角的变形

题目描述 :

         1
     1  1  1

  1  2  3  2  1
1  3  6  7  6  3  1
1  4  10 16 19  16 10  4  1

以上三角形的数阵,第一行只有一个数1,以下每行的每个数,是恰好是它上面的数,左上角数到右上角的数,3个数之和(如果不存在某个数,认为该数就是0)。
求第n行第一个偶数出现的位置。如果没有偶数,则输出-1。例如输入3,则输出2,输入4则输出3。
思路分析:
这一题 数学归纳法。
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    while(cin>>n){
        int res=0;
      if(n==1 || n==2)
      {
          res=0;
      }else if(n%2==1){
          res=2;
      }else if(n%4==0){
          res=3;
      }else if(n%2==0 && n%4!=0){
          res=4;
      }
        cout<<res<<endl;
    }
    return 0;
}

或者:


//思路:1.找规律,发现,如果用数组表示的话,第1行的1并不是在最左边,而是在第n个元素位置(n代表行号)
//     2.第n行的元素的第一个和最后一个是要提前赋值为1.其他行的元素,除第一个外,按照公式
//      a[i][j]=a[i][j-1]+a[i][j]+a[i][j+1];
#include<iostream>
#include<vector>
using namespace std;
void printYH(int n)
{

    vector<vector<int> >a(n,vector<int>(2*n-1,0));
    a[0][n-1]=a[n-1][0]=a[n-1][2*n-2]=1;
    if(n<2)
    {
        cout<<"-1"<<endl;
        return ;
    }
    for(int i=1;i<n;++i)
        for(int j=1;j<2*n-2;++j)
            a[i][j]=a[i-1][j]+a[i-1][j-1]+a[i-1][j+1];
    for(int i=0;i<2*n-1;++i)
        if(a[n-1][i]!=0 && (a[n-1][i]%2==0))
        {
            cout<<i+1<<endl;
            return ;
        }
    return ;                   
}
int main()
{
    int n;
    while(cin>>n)
    {
        printYH(n);
    }
    return 0;
}

53 . 表达式求值

题目描述 :

给定一个字符串描述的算术表达式,计算出结果值。

输入字符串长度不超过100,合法的字符包括”+, -, *, /, (, )”,”0-9”,字符串内容的合法性及表达式语法的合法性由做题者检查。本题目只涉及整型计算。
思路分析:
这一题 将中缀表达式转为后缀表达式,使用栈来进行计算。
代码:


//1.字符串预处理,针对可能出现的“{,},[,],-”等特殊情况进行替换,判断‘-’是负号还是减号,负号前面+0,转变成减法运算
//2.将中缀字符串转变为后缀字符串数组
//3.对后缀字符串数组进行求解
#include<iostream>
#include<vector>
#include<string>
#include<stack>
#include<sstream>
using namespace std;
bool cmpPriority(char top,char cur)//比较当前字符与栈顶字符的优先级,若栈顶高,返回true
{
    if((top=='+' || top=='-') && (cur=='+' || cur=='-'))
        return true;
 if((top=='*' || top=='/') && (cur=='+' || cur=='-'|| top=='*' || top=='/'))
        return true;
    if(cur==')')
        return true;
    return false;
}
void preProcess(string &str)//对字符串进行预处理
{
    for(int i=0;i<str.size();++i)
    {
        if(str[i]=='{')//将‘{、}、[,]’替换成'()'
            str[i]='(';
        else if(str[i]=='}')
            str[i]=')';
        else if(str[i]=='[')
            str[i]='(';
        else if(str[i]==']')
            str[i]=')';
        else if(str[i]=='-')
        {
            if(i==0)//将'-'前面添加0转变成减法运算
                str.insert(0,1,'0');
            else if(str[i-1]=='(')
                str.insert(i,1,'0');
  }
 }
}
vector<string> mid2post(string &str)
{
    vector<string>vstr;
    stack<char>cstack;
    for(int i=0;i<str.size();++i)//扫描字符串
    {
        string temp="";
        if(str[i]>='0' && str[i]<='9')//若是数字
        {
            temp+=str[i];
            while(i+1<str.size() && str[i+1]>='0' && str[i+1]<='9')
            {
                temp+=str[i+1];//若是连续数字
                ++i;
            }
            vstr.push_back(temp);
        }
        else if(cstack.empty() || str[i]=='(')//若栈空或者字符为'('
            cstack.push(str[i]);
        else if(cmpPriority(cstack.top(),str[i]))//若栈顶元素优先级较高,栈顶元素出栈
        {
            if(str[i]==')')//若当前字符是右括号,栈中元素出栈,入字符串数组中,直到遇到'('
            {
                while(!cstack.empty() && cstack.top()!='(')
                {
                    temp+=cstack.top();
                    cstack.pop();
                    vstr.push_back(temp);
                    temp="";
                }
                cstack.pop();                   
            }
            else//栈中优先级高的元素出栈,入字符串数组,直到优先级低于当前字符
            {
                while(!cstack.empty() && cmpPriority(cstack.top(),str[i]))
                {
                    temp+=cstack.top();
                    cstack.pop();
                    vstr.push_back(temp);
                    temp="";
                }
                cstack.push(str[i]);
   }
        }
        else//当前字符优先级高于栈顶元素,直接入栈
         cstack.push(str[i]);
    }
    while(!cstack.empty())//栈中还存在运算符时,出栈,存入字符串数组
    {
        string temp="";
        temp+=cstack.top();
        cstack.pop();
        vstr.push_back(temp);
    }
    return vstr;
}
int calcPostExp(vector<string> & vstr)//对后缀表达式进行求值,主要是根据运算符取出两个操作数进行运算
{
    int num,op1,op2;
    stack<int>opstack;
    for(int i=0;i<vstr.size();++i)
    {
        string temp=vstr[i];
        if(temp[0]>='0' && temp[0]<='9')//如果当前字符串是数字,利用字符串流转化为int型
        {
            stringstream ss;
            ss<<temp;
            ss>>num;
            opstack.push(num);
        }
        else if(vstr[i]=="+")//若是操作符,取出两个操作数,进行运算,并将结果存入
        {
            op2=opstack.top();
            opstack.pop();
            op1=opstack.top();
            opstack.pop();
            opstack.push(op1+op2);
        }
        else if(vstr[i]=="-")
        {
            op2=opstack.top();
            opstack.pop();
            op1=opstack.top();
            opstack.pop();
            opstack.push(op1-op2);
        }
        else if(vstr[i]=="*")
        {
            op2=opstack.top();
            opstack.pop();
            op1=opstack.top();
            opstack.pop();
            opstack.push(op1*op2);
        }
        else if(vstr[i]=="/")
        {
            op2=opstack.top();
            opstack.pop();
            op1=opstack.top();
            opstack.pop();
            opstack.push(op1/op2);
        }
    }
    return opstack.top();//最终的栈顶元素就是求解的结果
}
void calcExp(string str)
{
    vector<string>vstr;
    preProcess(str);//对字符串进行预处理
    vstr=mid2post(str);//将中缀表达式转为后缀,保存在字符串数组中,方便下一步求解
    int res=calcPostExp(vstr);
    cout<<res<<endl;
}
int main()
{
    string str;
    while(getline(cin,str))
    {
        calcExp(str);
 }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u011268787/article/details/78698817