华为上机笔试题

(1)求两个整数的最小公倍数

#include <iostream>
using namespace std;
int gcd(int a,int b);//用辗转相除法求最大公约数
int main()
{
    int a,b;
    cin>>a>>b;
    int res=a*b/gcd(a,b);
    cout<<res;
}
int gcd(int a,int b){
    return a%b==0?b:gcd(b,a%b);
}

基本思路就是先用辗转相除法求得两个数的最大公约数,然后两个数相乘除以最大公约数就得到了最小公倍数。

(2)不使用库函数求一个数的立方根
主要有两种思路,一种是用二分法,可令左初值为1,右初值为num,不断二分找根;另一种是用牛顿迭代法,直接用迭代公式求解。

二分法代码:

#include <algorithm>
#include <cmath>
#include <stdio.h>
using namespace std;
int main()
{
    double num;  //待处理的数
    scanf("%f",&num);
    const double err=0.001;   //允许的误差
    bool done=false;
    double start=1.0,end=num;
    double res;
    while(!done){
        double mid=(start+end)/2;
        if(abs(pow(mid,3)-num)<=err){
            res=mid;
            done=true;
        }
        else if(pow(mid,3)-num>err)
            end=mid;
        else
            start=mid;
    }
    printf("%.1f",res);
    return 0;
}

牛顿迭代法代码:

#include <algorithm>
#include <cmath>
#include <stdio.h>
using namespace std;
int main()
{
    double num;
    scanf("%lf",&num);
    const double err=0.000001;
    bool done=false;
    double xn=1;
    while(!done){
        if(abs(pow(xn,3)-num)<=err)
            done=true;
        else{
            xn=2.0/3.0*xn+num/(3*xn*xn);
        }
    }
    printf("%.1f",xn);
    return 0;
}

牛顿迭代公式\(x_{n+1}=x_n-\frac{f(x_n)}{f^*(x_n)}\),在本道题中相当于要求\(f(x)=x^3-num=0\)的解,所以只需要按照上述迭代公式进行求解就可以。

在实际过程中测试发现,二分法的速度远远慢于牛顿迭代法。
由于对输出小数点位数有要求所以输入输出采用stdio。

(3)将字符串逆序输出
这道题最简单的思路是用栈,因为栈具有先进后出的性质,但是利用string类型的变量能够直接用小标对每个字符进行操作的性质,显然更为简单,除此之外,还可以用头文件algorithm中的reverse()函数直接得到翻转后的字符串,用例reverse(s.begin(),s.end()),没有返回值,直接将翻转后的字符串保存回原始字符串。

#include <iostream>
#include <string>
using namespace std;
int main()
{
    string str;
    getline(cin,str);
    for(int i=str.length()-1;i>=0;i--)
        cout<<str[i];
    return 0;
}

在输入带空格的字符串时,不能直接用cin,因为cin遇到空格或回车等符号就认为输入结束,此时可以用getline获取一整行的输入。

(4)计负均正
从输入任意个整型数,统计其中的负数个数并求所有非负数的平均值,结果保留一位小数,如果没有非负数,则平均值为0,本题有多组输入数据,输入到文件末尾,请使用while(cin>>)读入,数据范围小于1e6。
这道题没有什么特殊的地方,就是需要主要while(cin>>)这种用法,需要运行ctrl+D 回车 才表示输入停止。

#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
    int num;//输入的数
    int negaNum=0;//输入的复数个数
    int noNegaNum=0;
    int sum=0;
    while(cin>>num){
        if(num<0)
            negaNum++;
        else{
            noNegaNum++;
            sum+=num;
        }
    }
    cout<<negaNum<<endl;
    double ave=0;
    if(noNegaNum>0)
        ave=sum/(double)noNegaNum;
    printf("%.1f",ave);
    return 0;
}

(5)Redraiment的走法
Redraiment是走梅花桩的高手。Redraiment可以选择任意一个起点,从前到后,但只能从低处往高处的桩子走。他希望走的步数最多,你能替Redraiment研究他最多走的步数吗?

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    int N;   //数组数目
    while(cin>>N){
        int arr[N];
        int dp[N];//dp[i]表示必须以arr[i]结尾的最长递增子序列
        for(int i=0;i<N;i++)
            cin>>arr[i];
        int maxNum=0;
        for(int i=0;i<N;i++){
            dp[i]=1;
            for(int j=0;j<i;j++){
                if(arr[i]>arr[j])
                    dp[i]=max(dp[i],dp[j]+1);
            }
            maxNum=max(maxNum,dp[i]);
        }
        cout<<maxNum<<endl;
    }
    return 0;
}

上述问题其实就是最长递增子序列的问题,可以用动态规划求解。

(6)字符统计
输入一个只包含小写英文字母和数字的字符串,按照不同字符统计个数由多到少输出统计结果,如果统计的个数相同,则按照ASCII码由小到大排序输出。

#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
int main()
{
    string str;
    int ascii[128] = { 0 };
    while (getline(cin, str)) {
        for (int i = 0; i < str.length(); i++)
            ascii[str[i]]++;
        int maxRepeatTimes = 0;    //记录多大的重复次数
        for (int i = 0; i < 127; i++)
            maxRepeatTimes = maxRepeatTimes > ascii[i] ? maxRepeatTimes : ascii[i];
        while (maxRepeatTimes) {
            for (int i = 0; i < 127; i++) {
                if (ascii[i] == maxRepeatTimes) {
                    printf("%c", i);
                    ascii[i] = 0;
                }
            }
            maxRepeatTimes--;
        }
        cout<<endl;
    }
    return 0;
}

这道题其实可以根据题目中限定只包含小写英文字母和数字去限定数组大小,即可以开辟比小于128的数组大小来保存每个字符出现的次数。

(7)排序
输入整型数组和排序标识,对其元素按照升序或降序进行排序(一组测试用例可能会有多组数据)本题有多组输入,请使用while(cin>>)处理

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool comp1(int a,int b){//降序
    return a>b;
}
bool comp2(int a,int b){//升序
    return a<b;
}
int main()
{
    int N; //数组元素个数
    while(cin>>N){
        vector<int>arr;
        for(int i=0;i<N;i++){
            int tmp;
            cin>>tmp;
            arr.push_back(tmp);
        }
        int flag;
        cin>>flag;
        if(flag)
            sort(arr.begin(),arr.end(),comp1);//降序排列
        else
            sort(arr.begin(),arr.end(),comp2);//降序排列
        for(int i=0;i<N;i++)
            cout<<arr[i]<<" ";
        cout<<endl;
    }
}

这道题考的其实就是最简答的排序算法,但是由于太久没练生疏了,所以选择直接用algorithm头文件里面的sort函数进行排序,这个函数默认是升序排列,不过它支持自己重写比较函数,可以实现升序、降序,甚至是自定义数据结构的排序。

(8)等差数列和
功能:等差数列 2,5,8,11,14。。。。
输入:正整数N >0
输出:求等差数列前N项和
本题为多组输入,请使用while(cin>>)等形式读取数据

#include <iostream>
using namespace std;
int main(){
    int N;
    int d=3;   //等比间隔
    int start=2;//初项
    while(cin>>N){
        int sum=N*start+N*(N-1)*d/2;
        cout<<sum;
        cout<<endl;
    }
    return 0;
}

这是一道很基础的题,等差数列通项\(a_n=a_1+(n-1)d\),求和公式\(S_n=na_1+\frac{n(n-1)}{2}d\)。等比数列通项\(a_n=a_1q^{n-1}\),求和公式\(S_n=\frac{a_1(1-q^n)}{1-q}\)

(9)自守数
自守数是指一个数的平方的尾数等于该数自身的自然数。例如:25^2 = 625,76^2 = 5776,9376^2 = 87909376。请求出n以内的自守数的数。

#include <iostream>
using namespace std;
bool isMorphicNum(int num) {
    int s = num * num;
    bool flag = true;
    while (num) {
        if ((num % 10) == (s % 10)) {
            num = num / 10;
            s = s / 10;
        }
        else {
            flag = false;
            break;
        }
    }
    return flag;
}
int main()
{
    int N;
    while(cin>>N){
        int num=0;
        for(int i=0;i<=N;i++){
            if(isMorphicNum(i))
                num++;
        }
        cout<<num;
        cout<<endl;
    }
}

这道题还有另外一种思路就是将结果转化为字符串来处理,比较平方字符串的后缀是不是和原始数据字符串一致。

(10)数字字符前后加星号
将一个字符中所有的整数前后加上符号"*",其他字符保持不变。连续的数字视为一个整数。注意:本题有多组样例输入。

#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
int main()
{
    string str;
    while(getline(cin,str)){
        bool pre=false;//用来表示一个字符前后是数字还是其他
        bool cur;//用来表示当前字符前后是数字还是其他
        for(int i=0;i<str.length();i++){
            cur=(str[i]>='0'&&str[i]<='9');
            if((!pre&&cur)||(pre&&!cur)){//前一个字符不是数字,当前字符是数字;或前一个字符是数字,当前字符不是数字
               printf("%c",'*');
            }
            printf("%c",str[i]);
            pre=cur;
        }
        if(str[str.length()-1]>='0'&&str[str.length()-1]<='9')
             printf("%c",'*');
        cout<<endl;
    }
    return 0;
}

(11)四则运算
输入一个表达式(用字符串表示),求这个表达式的值。保证字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。且表达式一定合法。

#include <iostream>
#include <string>
#include <stack>
using namespace std;
bool isDigital(char c){//判断一个字符是不是数字字符
    return c>='0'&&c<='9';
}
int compute(string &str,int pos){
    int L=str.length();
    stack<int>st;
    char flag='+';
    int tmp=0;//中间递归的结果
    while(pos<L){
        if(str[pos]=='{'||str[pos]=='('||str[pos]=='['){//碰到左括号,将结果计算交给递归
            pos++;
            tmp=compute(str,pos);
        }
        while(pos<L&&isDigital(str[pos])){//将连续的数字组合成一个完整的数
            tmp=tmp*10+str[pos]-'0';
            pos++;
        }
        switch(flag){
            case '+':st.push(tmp);break;
            case '-':st.push(-tmp);break;
            case '*':{
                int left=st.top();
                left*=tmp;
                st.pop();
                st.push(left);
                break;
            }
            case '/':{
                int left=st.top();
                left/=tmp;
                st.pop();
                st.push(left);
                break;
            }
        }
        tmp=0;
        flag=str[pos];
        if(str[pos]=='}'||str[pos]==']'||str[pos]==')'){
            pos++;
            break;
        }
        pos++;
    }
    int sum=0;
    while(st.size()){
        sum+=st.top();
        st.pop();
    }
    return sum;
}
int main()
{
    string str;
    cin>>str;
    int pos=0;   //表示当前遍历到的位置
    int res=compute(str,pos);
    cout<<res;
}

这道题比较难,目前上面的代码还没有通过,以后有时间再调。

(12)最小编辑距离
Levenshtein 距离,又称编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。编辑距离的算法是首先由俄国科学家Levenshtein提出的,故又叫Levenshtein Distance。
Ex:
字符串A:abcdefg
字符串B: abcdef
通过增加或是删掉字符”g”的方式达到目的。这两种方案都需要一次操作。把这个操作所需要的次数定义为两个字符串的距离。
要求:
给定任意两个字符串,写出一个算法计算它们的编辑距离
本题含有多组输入数据。

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    string str1,str2;
    while(cin>>str1>>str2){
        int N=str1.length();
        int M=str2.length();
        int dp[N+1][M+1];//dp[i][j]表示由str1[0,...,i-1]到str2[0,...,j-1]的最小编辑代价
        for(int j=0;j<=M;j++)//dp[0][j]表示空字符到str2[0,...,j-1]的编辑代价
            dp[0][j]=j;
        for(int i=0;i<=N;i++)//dp[i][0]表示由str1[0,...,i-1]到空字符的编辑代价
            dp[i][0]=i;
        for(int i=1;i<=N;i++){
            for(int j=1;j<=M;j++){
                if(str1[i-1]==str2[j-1])
                    dp[i][j]=dp[i-1][j-1];
                else{
                    dp[i][j]=min(dp[i-1][j]+1,dp[i][j-1]+1);
                    dp[i][j]=min(dp[i][j],dp[i-1][j-1]+1);
                }
            }
        }
        cout<<dp[N][M]<<endl;
    }
    return 0;
}

这其实是一道比较常规的动态规划的问题。所以用常规动态规划的方法去求解就行。不过目前没有考虑对原始动态规划进行空间优化。

(13)杨辉三角的变形
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。输入n(n <= 1000000000)本题有多组输入数据,输入到文件末尾,请使用while(cin>>)等方式读入。

#include <iostream>
using namespace std;
int main()
{
    int n;
    while(cin>>n){
        int res=-1;
        if(n==1||n==2)
            res=-1;
        else if(n>2&&n%2==1)
            res=2;
        else if(n>2&&n%4==0)
            res=3;
        else
            res=4;
        cout<<res<<endl;
    }
    return 0;
}

这道题因为给出的矩阵排版问题,本来应该排成等腰三角形,它排成直角三角形,导致题目理解上有点困难,不过理解了题目之后,这道题其实就是一道找规律的题,多写几行就能找到规律。

(14)挑7
输出7有关数字的个数,包括7的倍数,还有包含7的数字(如17,27,37...70,71,72,73...)的个数(一组测试用例里可能有多组数据,请注意处理。

#include <iostream>
using namespace std;
bool isContain7(int n){//判断这个数的各个数位是否包含7
    bool res=false;
    while(n){
        if(n%10==7){
            res=true;
            break;
        }
        n/=10;
    }
    return res;
}
int main(){
    int N;
    while(cin>>N){
        int res=0;
        for(int i=1;i<=N;i++){
            if((i%7==0)||(isContain7(i))){//是7的整数倍或某个数位包含7
                res++;
                continue;
            }
        }
        cout<<res<<endl;
    }
    return 0;
}

这道题本来想分(<10),(<100),...这个去找7的倍数,包含7的分别有多少,期望能有一些规律,但是由于7的倍数和含7的数之间是有重合的,这样做很麻烦,所以决定直接用暴力判断。

(15)完全数计算
完全数(Perfect number),又称完美数或完备数,是一些特殊的自然数。它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。例如:28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4+7+14=28。s输入n,请输出n以内(含n)完全数的个数。计算范围, 0 < n <= 500000本题输入含有多组样例。

#include <iostream>
using namespace std;
bool isPerfectNum(int n){//判断一个数是不是完全数
    int res=false;
    int sum=0;
    for(int i=1;i<=n/2;i++){
        if(n%i==0)
            sum+=i;
    }
    res=(sum==n);
    return res;
}
int main(){
    int N;
    while(cin>>N){
        int res=0;
        for(int i=2;i<=N;i++){
            if(isPerfectNum(i))
                res++;
        }
        cout<<res<<endl;
    }
    return 0;
}

这道题其实思路很直观,就去遍历判断一个数是不是完全数,但是这样其实运行时间很长。看牛客上很多人的代码就是事先知道了允许的最大输入范围内的完全数只有4个,然后做简单的判断就行了。这是一种钻空子的写法,但是应付这种笔试题还是可以的。

(16)高精度整数加法
输入两个用字符串表示的整数,求它们所表示的数之和。字符串的长度不超过10000。本题含有多组样例输入。

#include <iostream>
#include <string>
#include <algorithm>
#include <stack>
using namespace std;
int main(){
    string str1,str2;
    while(cin>>str1>>str2){
        int carr=0;           //保存进位
        stack<char>s1,s2;     //保存两个加数字符
        stack<char>sRes;      //保存结果字符
        for(int i=0;i<str1.length();i++)
            s1.push(str1[i]);
        for(int i=0;i<str2.length();i++)
            s2.push(str2[i]);
        while(!s1.empty()&&!s2.empty()){
            int sum=(s1.top()-'0')+(s2.top()-'0')+carr;//从低位开始对应位相加(注意还要加上上一次进位)
            carr=sum/10;//保存新的进位
            int res=sum%10;//扣除进位后剩余的数
            sRes.push((char)(res+'0'));
            s1.pop();
            s2.pop();
        }
        if(str1.length()>=str2.length()){
            while(!s1.empty()){
                int sum=(s1.top()-'0')+carr;
                carr=sum/10;//保存新的进位
                int res=sum%10;//扣除进位后剩余的数
                sRes.push((char)(res+'0'));
                s1.pop();
            }
        }
        else {
            while(!s2.empty()){
                int sum=(s2.top()-'0')+carr;
                carr=sum/10;//保存新的进位
                int res=sum%10;//扣除进位后剩余的数
                sRes.push((char)(res+'0'));
                s2.pop();
            }
        }
       if(carr!=0)
          sRes.push((char)(carr+'0'));
        while(!sRes.empty()){
            cout<<sRes.top();
            sRes.pop();
        }
        cout<<endl;
    }
}

这道题难度也不是很大,只要注意进位的处理就可以了,直接想到用栈进行处理省得自己去处理下标索引,但是这样做增加了额外的空间消耗。

(17)输出最小的k个整数
输入n个整数,输出其中最小的k个。本题有多组输入样例,请使用循环读入,比如while(cin>>)等方式处理。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
    int N,k;
    while(cin>>N>>k){
        vector<int>arr;
        for(int i=0;i<N;i++){
            int tmp;
            cin>>tmp;
            arr.push_back(tmp);
        }
        sort(arr.begin(), arr.end());
        for(int i=0;i<k;i++)
             cout<<arr[i]<<" ";
        cout<<endl;
    }
}

这道题很容易想到的就是排序算法。

(18)找出字符串中第一个只出现一次的字符

#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    while(cin>>str){
        int ascii[128]={0};
        bool flag=false;
        for(int i=0;i<str.length();i++)
            ascii[str[i]]++;
        for(int i=0;i<str.length();i++){
            if(ascii[str[i]]==1){
                cout<<str[i];
                flag=true;
                break;
            }
        }
        if(!flag)
            cout<<"-1";
        cout<<endl;
    }
    return 0;
}

(19)查找组成一个偶数差值最接近的一个素数对
任意一个偶数(大于2)都可以由2个素数组成,组成偶数的2个素数有很多种情况,本题目要求输出组成指定偶数的两个素数差值最小的素数对。本题含有多组样例输入。

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
bool isPrimeNum(int n){//判断一个数是不是素数
    if(n<2)
        return false;
    bool res=true;
    double N=sqrt((double)n);
    for(int i=2;i<=N;i++){
        if(n%i==0){
            res=false;
            break;
        }     
    }
    return res;
}
int main(){
    int n;
    while(cin>>n){
        int prime1,prime2;
        int minD=INT32_MAX;
        for(int i=2;i<=n/2;i++){
            if(isPrimeNum(i)&&isPrimeNum(n-i)){//两个数加数都是素数
                int D=n-i-i;
                if(minD>D){
                    minD=D;
                    prime1=i;
                    prime2=n-i;
                }
            }
        }
        cout<<prime1<<endl<<prime2<<endl;
    }
}

这道题其实思路也比较简单,最重要的就是判断一个数是否是素数,只需要在\(2\rightarrow\sqrt{n}\)范围内判断是否有整除\(n\)的数就行。

(20)放苹果问题
把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。数据范围:0<=m<=10,1<=n<=10。本题含有多组样例输入。

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

这道题还可以用动态规划的方法做,但是没有写,有时间再研究动态规划的方法。

(21)输入整数的二进制形式中1的个数
输入一个正整数,计算它在二进制下的1的个数。注意多组输入输出!!!!!!

#include <iostream>
using namespace std;
int main(){
    int n;
    while(cin>>n){
        int sum=0;
        while(n){
            if(n&1==1)
                sum++;
            n=n>>1;
        }
        cout<<sum<<endl;
    }
}

这道题其实是一个很基本的位运算。

(22)DNA序列
一个DNA序列由A/C/G/T四个字母的排列组合组成。G和C的比例(定义为GC-Ratio)是序列中G和C两个字母的总的出现次数除以总的字母数目(也就是序列长度)。在基因工程中,这个比例非常重要。因为高的GC-Ratio可能是基因的起始点。给定一个很长的DNA序列,以及要求的最小子序列长度,研究人员经常会需要在其中找出GC-Ratio最高的子序列。本题含有多组样例输入。

#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    while(cin>>str){
        const int N=str.length();
        int L;
        cin>>L;
        int *CG=new int[N]();//CG[i]表示str[0,...,i]中共有多少个C或G
        int cnt=0;
        for(int i=0;i<N;i++){
            if(str[i]=='C'||str[i]=='G')
                cnt++;
            CG[i]=cnt;
        }
        int start=0;
        int maxNum=0;
        for(int i=0;i<N-L+1;i++){
            int num=CG[i+L-1]-CG[i];//子序列中包含的CG总个数
            if(str[i]=='C'||str[i]=='G')
                num++;
            if(maxNum<num){
                maxNum=num;
                start=i;
            }
        }
        delete[]CG;
        for(int i=start;i<start+L;i++){
            cout<<str[i];
        }
        cout<<endl;
    }
}

这道题我觉得有意思的地方在于如何快速地找到一个子串里面包含的C和G的总数,所以这边创建了一个CG数组用来保存当前从0到当前位置处的总的C和G的数目。这是一道滑动窗口的题,可以考虑用双指针的方法,可能会更简单一点。

(23)输出两个字符串的最长公共子串
查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。注:子串的定义:将一个字符串删去前缀和后缀(也可以不删)形成的字符串。请和“子序列”的概念分开!本题含有多组输入数据!

#include <iostream>
#include <string>
using namespace std;
int main(){
    string str1,str2;
    while(cin>>str1>>str2){
        int N=str1.length();
        int M=str2.length();
        int dp[N][M];//dp[i][j]表示str1[0,...,j]和str2[0,..,j]的最长公共子串
        for(int i=0;i<N;i++)
            dp[i][0]=(str1[i]==str2[0])?1:0;
        for(int j=0;j<M;j++)
            dp[0][j]=(str1[0]==str2[j])?1:0;
        int maxL=0;//保存最大的子串长度
        int end1=0,end2=0;//保存最长子串在str1和str2中对应的结束位置
        for(int i=1;i<N;i++){
            for(int j=1;j<M;j++){
                dp[i][j]=(str1[i]==str2[j])?dp[i-1][j-1]+1:0;
                if(dp[i][j]>maxL){
                    maxL=dp[i][j];
                    end1=i;
                    end2=j;
                }
            }
        }
        string substring;
        substring=(N<M)?str1.substr(end1-maxL+1,maxL):str2.substr(end2-maxL+1,maxL);
        cout<<substring<<endl;
    }
}

这道题其实是经典的动态规划的题目,需要注意的是要分清楚子串和子序列之间的差别。还有上述代码在牛客上只通过了60%,找不出问题。

(24)学生信息排序
查找和排序题目:输入任意(用户,成绩)序列,可以获得成绩从高到低或从低到高的排列,相同成绩都按先录入排列在前的规则处理。

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
struct info {//定义学生信息结构体
    string name;
    int scope;
};
bool ascend(struct info s1, struct info s2) {//升序函数
    return s1.scope < s2.scope;
}
bool decend(struct info s1, struct info s2) {//降序排列
    return s1.scope > s2.scope;
}
int main() {
    int N; //表示人数
    while (cin >> N) {
        int flag;   //排序方式,0表示从高到低,1表示从低到高
        cin >> flag;
        vector<struct info>s;
        for (int i = 0; i < N; i++) {
            struct info stu;
            cin >> stu.name;
            cin >> stu.scope;
            s.push_back(stu);
        }
        if (flag)
            sort(s.begin(), s.end(), ascend);
        else
            sort(s.begin(), s.end(), decend);
        for (int i = 0; i < N; i++) {
            cout << s[i].name << " " << s[i].scope << endl;
        }
    }
}

这道问题我的做法是利用头文件algorithm里面的sort函数,但是当有两个人的成绩相同的话,结果可能出错,暂时没有再往下调。

(25)矩阵乘法

#include <iostream>
using namespace std;
int main(){
    int M,N,H;
    while(cin>>M>>N>>H){
        int A[M][N];
        int B[N][H];
        int C[M][H];
        for(int row=0;row<M;row++)
            for(int col=0;col<N;col++)
                cin>>A[row][col];
        for(int row=0;row<N;row++)
            for(int col=0;col<H;col++)
                cin>>B[row][col];
        for(int i=0;i<M;i++){
            for(int j=0;j<H;j++){
                C[i][j]=0;
                for(int k=0;k<N;k++)
                    C[i][j]+=A[i][k]*B[k][j];
            }
        }
        for(int i=0;i<M;i++){
            for(int j=0;j<H;j++){
                cout<<C[i][j]<<" ";
            }
            cout<<endl;
        }
    }
    return 0;
}

这道题目原原本本按照矩阵乘法来做,没有任何拐弯的地方。

(26)计算某字母出现的次数
写出一个程序,接受一个由字母、数字和空格组成的字符串,和一个字母,然后输出输入字符串中该字母的出现次数。不区分大小写。

#include <iostream>
#include <string>
using namespace std;
bool isUpper(char c){//判断是否是大写字母
    return c>='A'&&c<='Z';
}
bool isLower(char c){//判断是否是小写字母
    return c>='a'&&c<='z';
}
char upper2Lower(char c){//大写字母转化为小写字母
    return c-'A'+'a';
}
char lower2Upper(char c){//小写字母转化为大写字母
    return c-'a'+'A';
}
int main(){
    string str;
    char trgt;
    getline(cin,str);
    cin>>trgt;
    char trgt2=isLower(trgt)?lower2Upper(trgt):upper2Lower(trgt);
    int sum=0;
    for(int i=0;i<str.length();i++){
        if(str[i]==trgt||str[i]==trgt2)
            sum++;
    }
    cout<<sum;
    return 0;
}

这道题其实挺简单,重要的是要懂得判断输入字母的大小写,以及大小写字母之间的相互转换。

(27)明明的随机数
明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作(同一个测试用例里可能会有多组数据(用于不同的调查),希望大家能正确处理)。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
    int N;
    while(cin>>N){
        int arr[1000]={0};
        for(int i=0;i<N;i++){
            int tmp;
            cin>>tmp;
            arr[tmp]++;
        }
        for(int i=0;i<=1000;i++){
            if(arr[i]>0)
                cout<<i<<endl;
        }
    }
    return 0;
}

(28)字符串分割
连续输入字符串,请按长度为8拆分每个字符串后输出到新的字符串数组;长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。

#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    while(cin>>str){
        int L=str.length();
        int N=L/8+1;       
        N=L%8==0?N-1:N;   //需要输出的字符串数目
        int M=N*8-L;      //需要补的零的数目
        for(int i=0;i<N-1;i++)//前面N-1个可以统一处理
            cout<<str.substr(i*8,8)<<endl;
        cout<<str.substr((N-1)*8);//最后一个需要单独处理
        for(int i=0;i<M;i++)
            cout<<'0';
        cout<<endl;
    }
    return 0;
}

(29)进制转换
写出一个程序,接受一个十六进制的数,输出该数值的十进制表示。

#include <iostream>
#include <string>
#include <cmath>
using namespace std;
int trans(char c){//输出16进制各个字符代表的10进制的数
    int res;
    switch(c){
        case '0':res=0;break;
        case '1':res=1;break;
        case '2':res=2;break;
        case '3':res=3;break;
        case '4':res=4;break;
        case '5':res=5;break;
        case '6':res=6;break;
        case '7':res=7;break;
        case '8':res=8;break;
        case '9':res=9;break;
        case 'A':
        case 'a':res=10;break;
        case 'B':
        case 'b':res=11;break;
        case 'C':
        case 'c':res=12;break;
        case 'D':
        case 'd':res=13;break;
        case 'E':
        case 'e':res=14;break;
        case 'F':
        case 'f':res=15;break;
    }
    return res;
}
int main(){
    string str;
    while(cin>>str){
        int L=str.length();
        long long dat=0;
        int wei=0;
        for(int i=L-1;i>=2;i--){
            dat+=pow(16,wei)*trans(str[i]);
            wei++;
        }
        cout<<dat<<endl;
    }
    return 0;
}

这道题也算是常规题,没有什么可讲的。

(30)求一个正整数的质因数
功能:输入一个正整数,按照从小到大的顺序输出它的所有质因子(重复的也要列举)(如180的质因子为2 2 3 3 5 )最后一个数后面也要有空格

#include <iostream>
using namespace std;
long getMinPrime(long dat){//获取一个数的最小质因数
    if(dat==1||dat==2||dat==3||dat==5||dat==7)
        return dat;
    for(int i=2;i<dat;i++)
        if(dat%i==0)
            return i;
    return dat;
}
int main(){
    long num;
    cin>>num;
    int i;

    while(1){
        long minP=getMinPrime(num);
        cout<<minP<<" ";
        if(minP==num){
            return 0;
        }
        else{
            num=num/minP;
        }
    }
    return 0;
}

这道题不知道为什么,感觉思路挺简单的,但是运行就超时,而且用别人测试通过的代码运行也超时,看来可能真的跟电脑状态有关。

(31)取近似值
写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于5,向上取整;小于5,则向下取整。

#include <iostream>
using namespace std;
int main(){
    float dat;
    cin>>dat;
    long long num=(long long)(dat+0.5);
    cout<<num;
    return 0;
}

(32)合并数据表
数据表记录包含表索引和数值(int范围的正整数),请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。

#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>
using namespace std;
struct info{
   int key;
   int value;
};
bool comp(struct info s1,struct info s2){
    return s1.key<s2.key;
}
int main(){
    int N; //键值对的个数
    cin>>N;
    unordered_map<int, int>mp;
    for(int i=0;i<N;i++){
        pair<int,int>tmp;
        cin>>tmp.first;
        cin>>tmp.second;
        if(mp.find(tmp.first)!=mp.end())
            mp[tmp.first]+=tmp.second;
        else
            mp[tmp.first]=tmp.second;
    }
    vector<struct info>s;
    for(auto it=mp.begin();it!=mp.end();it++){
        struct info tmp;
        tmp.key=it->first;
        tmp.value=it->second;
        s.push_back(tmp);
    }
    sort(s.begin(),s.end(),comp);
    for(int i=0;i<s.size();i++)
        cout<<s[i].key<<" "<<s[i].value<<endl;
    return 0;
}

这道题用哈希表可以非常简便地解决问题,可以好好体会一下。

(33)提取不重复的整数
输入一个int型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。保证输入的整数最后一位不是0。

#include <iostream>
#include <unordered_map>
using namespace std;
int main(){
    int num;
    cin>>num;
    unordered_map<int,int>mp;
    int res=0;
    while(num){
        int tmp=num%10;
        if(mp[tmp]==0){
            mp[tmp]=1;
            res=res*10+tmp;
        }
        num=num/10;
    }
    cout<<res;
    return 0;
}

用哈希表就很容易

(34)字符个数统计
编写一个函数,计算字符串中含有的不同字符的个数。字符在ACSII码范围内(0~127),换行表示结束符,不算在字符里。不在范围内的不作统计。多个相同的字符只计算一次例如,对于字符串abaca而言,有a、b、c三种不同的字符,因此输出3。

#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
int main(){
    string str;
    cin>>str;
    int sum=0;
    int ascii[128]={0};
    for(int i=0;i<str.length();i++){
        if(str[i]>=0&&str[i]<=127)
            ascii[str[i]]++;
    }
    for(int i=0;i<128;i++){
        if(ascii[i]!=0)
            sum++;
    }
    cout<<sum;
    return 0;
}

(35)数字颠倒
输入一个整数,将这个整数以字符串的形式逆序输出,程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001

#include <iostream>
using namespace std;
int main(){
    int num;
    cin>>num;
    while(num){
        int tmp=num%10;
        num/=10;
        cout<<tmp; 
    }
    return 0;
}

(36)字符串翻转
接受一个只包含小写字母的字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main(){
    string str;
    cin>>str;
    reverse(str.begin(), str.end());
    cout<<str;
    return 0;
}

(37)句子逆序
将一个英文语句以单词为单位逆序排放。例如“I am a boy”,逆序排放后为“boy a am I”所有单词之间用一个空格隔开,语句中除了英文字母外,不再包含其他字符

#include <iostream>
#include <string>
#include <stack>
using namespace std;
int main(){
    string str;
    getline(cin,str);
    stack<string>s;
    int pre=-1;  //保存上一个空格在字符串中的位置
    for(int i=0;i<str.length();i++){
        if(str[i]==' '){
            int cur=i;
            string tmp=str.substr(pre+1,cur-pre-1);
            s.push(tmp);
            pre=cur;
        }  
        if(i==str.length()-1){
            string tmp=str.substr(pre+1,i-pre);
            s.push(tmp);
        }
    }
    while(!s.empty()){
        cout<<s.top()<<" ";
        s.pop();
    }
    return 0;
}
posted @ 2021-04-15 15:53  平和少年  阅读(607)  评论(0编辑  收藏  举报