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

54. 挑7

题目描述 :
输出7有关数字的个数,包括7的倍数,还有包含7的数字(如17,27,37…70,71,72,73…)的个数

思路分析:
这个问题有一个很好的解决办法就是将数字转为字符型,然后查找看字符里面有没有的符合条件的 字符 ,然后再判断是否数字能否整除7
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    while(cin>>n){
        //分为两个存在7倍数  和 数字里有7的数字
        int count=0;
        string s;
        int res=0;
        for(int i=7;i<=n;i++){
            stringstream ss;
            ss<<i;
            ss>>s;
            if(s.find('7')!=s.npos || i%7 ==0){
                count++;
            }
        } 
        cout<<count<<endl;
    }
    return 0;
}

或者

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    while(cin>>n){
        int cnt=0;
        for(int i=7;i<=n;i++){
            int temp=i;
            if(i%7==0){
                cnt++;
            }else{
                while(temp!=0){
                    if(temp%10==7)
                    {
                        ++cnt;
                        break;
                    }
                    temp=temp/10;
                }
            }

        }
        cout<<cnt<<endl;
    }
    return 0;
}

55. INOC产品部完全数计算

题目描述 :
完全数(Perfect number),又称完美数或完备数,是一些特殊的自然数。

它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。

例如:28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4+7+14=28。

给定函数count(int n),用于计算n以内(含n)完全数的个数。计算范围, 0 < n <= 500000

返回n以内完全数的个数。 异常情况返回-1

思路分析:
这个计算还是比较简单,但是我感觉我的方法应该不是计算速度最快的。主要思想就是遍历计算。
代码:

#include<bits/stdc++.h>
using namespace std;
bool perfect_num(int n){
    vector<int>sv;
    for(int i=1;i<n;i++){
        if(n%i==0)
        {
            sv.push_back(i);
        }

    }
    int sum=0;
    for(int i=0;i<sv.size();i++){
        sum+=sv[i];
    }
    if(sum==n)
        return true;
    else 
        return false;
}
int main(){
    int n;
    while(cin>>n){
        int count=0;
        for(int i=1;i<=n;i++){
            if(perfect_num(i))
                count++;
        }
        cout<<count<<endl;
    }
    return 0;
}

更加优化的计算方式:
#include<bits/stdc++.h>
using namespace std;
bool is_perfect_num(int i){
    int sum=0;
    int j=1;
    int t=i/2;
    while(j<t){
        if(i%j==0){
            sum+=j;
            if(j!=1){
                t=i/j;
                if(j!=i/j)
                    sum+=i/j;
            }
        }
        ++j;
        if(sum>i)
            return false;
    }
    return (sum==i)?true:false;
}
int count_perfect_num(int n){
    if(n<=0 || n>500000) return -1;
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(is_perfect_num(i))
            ++cnt;
    }
    return cnt;
}

int main(){
    int range;
    while(cin>>range){
        cout<<count_perfect_num(range)<<endl;
    }
    return 0;
}

56. 高精度整数加法

题目描述 :
在计算机中,由于处理器位宽限制,只能处理有限精度的十进制整数加减法,比如在32位宽处理器计算机中,
参与运算的操作数和结果必须在-231~231-1之间。如果需要进行更大范围的十进制整数加法,需要使用特殊
的方式实现,比如使用字符串保存操作数和结果,采取逐位运算的方式。如下:
9876543210 + 1234567890 = ?
让字符串 num1=”9876543210”,字符串 num2=”1234567890”,结果保存在字符串 result = “11111111100”。
-9876543210 + (-1234567890) = ?
让字符串 num1=”-9876543210”,字符串 num2=”-1234567890”,结果保存在字符串 result = “-11111111100”。

思路分析:
这个题目就是通过
代码:

#include <iostream>
#include <algorithm>
#include <sstream>
using namespace std;
int strComp(string &s1, string &s2)//返回0,表示len1>len2
{
    int len1 = s1.length();
    int len2 = s2.length();
    if (len1>len2)
        return 0;
    else if (len1<len2)
        return 1;
    else
    {
        if (s1 >= s2)
            return 0;
        else
            return 1;
    }
}
string itos(long long tmp)
{
    stringstream ss;
    ss << tmp;
    string s1 = ss.str();
    return s1;
}

string add1(string numStr1, string numStr2) //两个都是正
{
    string res;
    int c = 0, temp;
    if (numStr1.size() != numStr2.size())
    {                                           //长度不同先补零
        while (numStr1.size() < numStr2.size())
        {
            numStr1.insert(0, 1, '0');
        }
        while (numStr1.size() > numStr2.size())
        {
            numStr2.insert(0, 1, '0');  //在0下标元素前面插一个0
        }
    }

    for (int i = numStr1.size() - 1; i >= 0; i--)
    {                                                    //按位相加,从低位开始
        temp = (numStr1[i] - '0') + (numStr2[i] - '0') + c;
        if (temp>9)
        {
            temp = temp % 10;
            c = 1;        
        }
        else
            c = 0;
        res += itos(temp);
    }
    if (c == 1)  res += '1';//最高位还有进位,则补1个'1'
    reverse(res.begin(), res.end());//逆置字符串后结果就是相加后的值(res是从低位往里添加字符的)
    return res;
}




string add2(string numStr1, string numStr2) //两个都是负
{
    string res;
    int c = 0, temp;
    if (numStr1.size() != numStr2.size())
    {                                           //长度不同先补零
        while (numStr1.size() < numStr2.size())
        {
            numStr1.insert(1, 1, '0');
        }
        while (numStr1.size() > numStr2.size())
        {
            numStr2.insert(1, 1, '0');  //在1下标元素前面插一个0
        }
    }
    for (int i = numStr1.size() - 1; i>0; i--)
    {                                                  //最高位不管
        temp = (numStr1[i] - '0') + (numStr2[i] - '0') + c;
        if (temp>9)
        {
            temp = temp % 10;
            c = 1;
        }
        else
            c = 0;
        res += itos(temp);
    }
    if (c)res += '1';//最高位
    res += '-';      //添加'-'
    reverse(res.begin(), res.end());
    return res;
}

string add3(string numStr1, string numStr2) //一正一负
{
    string res;
    int flag = 0;
    int c = 0, temp;
    string a, b;//a-b a是被减数 b是减数 带负号的给减数
    if (numStr1[0] == '-') { b = numStr1; a = numStr2; }
    else{ b = numStr2; a = numStr1; }
    b = b.substr(1);
    if (a.size() != b.size())
    {                                           //长度不同先补零
        while (a.size() < b.size())
        {
            a.insert(0, 1, '0');
        }
        while (a.size() > b.size())
        {
            b.insert(0, 1, '0');  //在0下标元素前面插一个0
        }
    }
    if (strComp(a, b) == 1)
    {
        string t = b;
        b = a;
        a = t;
        flag = 1;
    }

    for (int i = a.size() - 1; i>=0; i--)
    {                                                  //最高位不管
        temp = (a[i] - '0')-(b[i] - '0')-c;
        if (temp<0)
        {
            temp =temp+10;
            c = 1;
        }
        else
            c = 0;
        res += itos(temp);
    }
    if(flag==1)res += '-';      //添加'-'
    reverse(res.begin(), res.end());
    return res;
}

int main()
{
    string numStr1, numStr2;
    while (cin >> numStr1 >> numStr2)
    {
        string result;
        if (numStr1[0] != '-'&&numStr2[0] != '-') result = add1(numStr1, numStr2);
        else if (numStr1[0] == '-'&&numStr2[0] == '-') result = add2(numStr1, numStr2);
        else result = add3(numStr1, numStr2);
        cout << result << endl;
    }
    system("pause");
    return 0;
}

57. 输入n个整数,输出其中最小的k个

题目描述 :
输入说明
1 输入两个整数 (一个是数组的大小,一个是输出数组的大小)
2 输入一个整数数组
输出一个整数数组

思路分析:
这个题目问题,其实思路不难,你先排序,然后在把最小的几个数字给输出出来就行了。但是由于我基本功还不够扎实,然后在一些细节上栽了跟头,一个就是vector容器不需要自己造轮子写swap函数,还有一个就是你用swap函数的时候,不需要在意是否取了指针放进去,直接用vector的数组就可以了。还有一个就是在排序的时候出现了一些问题,感觉很尴尬,要好好努力。

代码:

#include<bits/stdc++.h>
using namespace std;
int RandomInRange(int start,int end){
    if(end>start){
        srand(time(NULL));
        return start+rand()%((end-start)); //产生start ~end 之间的随机数
    }
    return 0;
}
void swap(int* a,int* b){
    int temp=*a;
    *a=*b;
    *b=temp;
}

int partion(vector<int>& numbers,int start,int end,int length ){
    if(numbers.empty() || start<0 ||end >=length || length<=0)
        exit(0);
    int index=RandomInRange(start,end);
    swap(&numbers[index],&numbers[end]);
    int small=start-1;
    for(index=start;index<end;++index){
        if(numbers[index]<numbers[end]){
            ++small;
            if(small!=index){
                swap(&numbers[index],&numbers[small]);
            }
        }
    }
    ++small;
    swap(&numbers[small],&numbers[end]);
    return small;
}

void quic_sort(vector<int>& numbers,int start,int end,int length){
    if(start==end)
        return;
    int index=partion(numbers,start,end,length);
    if(index>start)
        quic_sort(numbers,start,index-1,length);
    if(index<end)
        quic_sort(numbers,index+1,end,length);

}

int main(){
    int num,result_num;
    while(cin>>num>>result_num){
        vector<int>numbers;
        int temp;
        for(int i=0;i<num;i++)
        {
            cin>>temp;
            numbers.push_back(temp);
        }
        quic_sort(numbers,0,num-1,num);
        for(int i=0;i<result_num-1;i++)
        {
            cout<<numbers[i]<<" ";
        }
        cout<<numbers[result_num-1]<<endl;
    }
    return 0;
}

58. 找出字符串第一个只出现一次的字符

题目描述 :
输入说明
输入一个非空字符串
输出第一个只出现一次的字符,如果不存在输出-1

思路分析:
这个题目没想到特别好的方法,当时脑子里面只有一个想法就是用stack,因为,如果进来一个字母,然后发现前面的字母和自己一样就消失,这样就可以完美解决问题,但是自己还是太年轻。这样会导致一个问题就是,如果奇数个字母会出现错误(假设不论这个stack是否能实现)。然后我偷看了牛客上其他人的解答,有一个很不错的解答思路,就是 用find函数和rfind 函数,因为find函数,是从正面找字符,然后返回字母的位置,而rfind函数是找到字母最后出现的位置。因此只要 这两者一样就能解决问题。

代码:

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

int main(){
    string str;
    while(cin>>str){
        int i;
        for( i=0;i<str.length();i++){
            if(str.find(str[i])==str.rfind(str[i])){
                cout<<str[i]<<endl;
                break;
            }
        }
         if(i==str.length())
               cout<<-1<<endl; 
    }
    return 0;
}

59. 放苹果

题目描述 :
题目描述
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
输入
每个用例包含二个整数M和N。0<=m<=10,1<=n<=10。

思路分析:
这个题目应用递归可以很方便的解答。主要就是将分苹果,按照两个情况来,一个就是存在空盘子,还有一个就是没有空盘子。
还有一个需要注意的地方就是,没有苹果的时候,也是一种分法。

代码:

#include<bits/stdc++.h>
using namespace std;
//有盘子
int put_apple(int m,int n){
    if(m<0)
        return 0;
    if(m==1 || n==1 || m==0)
        return 1;
    return put_apple(m,n-1)+put_apple(m-n,n);
}
int main(){
    int n,m;
    while(cin>>m>>n){
        cout<<put_apple(m,n)<<endl;
    }
    return 0;
}

60. 查找输入整数二进制中1的个数

题目描述 :
输入一个整数
计算整数二进制中1的个数

思路分析:
这一题在剑指offer中有,基本思想就是数字向右移,并和1相与 不为0 就加1

代码:

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

61. DNA序列

题目描述 :
输入一个string型基因序列,和int型子串的长度
找出GC比例最高的子串,如果有多个输出第一个的子串
思路分析:
开始的时候基本思路没错,后面想 复杂了,其实就是你一个个地遍历过去,然后,比照前面的比例,如果后面的比例大于之前的,你就覆盖之前的。开始的时候我整了一个>=简直愚蠢,还整了一个deque进行存储,完全没有必要,用str.substr()完全够用。

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    string str;
    int n;
    while(cin>>str>>n){
      int max=0;  
      int index=0;
        for(int i=0;i<str.length()-n;i++){
            string son_str=str.substr(i,i+n);
            int counter=0;
            for(int j=0;j<n;j++){
                if(son_str[j]=='C' || son_str[j]=='G')
                    counter++;
            }
            if(max<counter){
                index=i;
                max=counter;
            }
        }
        cout<<str.substr(index,n)<<endl;
    }
    return 0;
}

62. MP3光标位置

题目描述 :
输入:
输入说明:
1 输入歌曲数量
2 输入命令 U或者D
输出:
1 输出当前列表
2 输出当前选中歌曲
思路分析:
这一题学到的一个东西scanf("%d",&n)成功输入多少个变量就返回多少值。经常可以这么用while (scanf("%d", &n) == 1)
这道题最重要的就是细致分析每一个情况。

代码:

/* 维护当前屏幕上,顶端歌曲名称cur_head,指针偏置位移0<=cur_pos<4 */
#include <cstdio>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

string s;

int main() {
    int n;
    while (scanf("%d", &n) == 1) {
        cin >> s;
        int cur_head = 1, cur_pos = 0;
        if (n <= 4) {
            for (int i = 0; i < (int)s.size(); i++) {
                if (s[i] == 'U') {
                    cur_pos = (cur_pos + n - 1) % n;
                } else {
                    cur_pos = (cur_pos + 1) % n;
                }
            }
        } else {
            for (int i = 0; i < (int)s.size(); i++) {
                if (s[i] == 'U'){
                    if(cur_head == 1 && cur_pos == 0){
                        cur_head = n - 3;
                        cur_pos = 3;
                    }else{
                        if(cur_pos > 0){
                            cur_pos--;
                        }else{
                            cur_head--;
                        }
                    }
                }else{
                    if(cur_head == n - 3 && cur_pos == 3){
                        cur_head = 1;
                        cur_pos = 0;
                    } else {
                        if(cur_pos < 3){
                            cur_pos++;
                        } else {
                            cur_head++;
                        }
                    }
                }
            }
        }
        for (int i = 0; i < min(n, 4); i++) {
            if (i) {
                printf(" ");
            }
            printf("%d", cur_head + i);
        }
        printf("\n%d\n", cur_head + cur_pos);
    }
    return 0;
}

63. 查找两个字符串a,b中的最大公共子串

题目描述 :
输入:
输入说明:
输入两个字符串
输出:
返回重复出现的字符
思路分析:
这一题,其实不难,但是我当时卡了,到最后冷静理清了一下思路,问题还是解决了,说明我的底子还是薄。当时问题出在了两个地方,一个就是for(int i=stand_len;i>0 && str_result==" ";i--) 我当时没有用&& str_result==" "这个语句的作用就是相当于判断,最大的子串是否已经被赋值了。
还有一个就是continue;这个是最精髓的,如果之前的子串不符合要求,就继续找下一个子串。而我之前在这个位置用的break;导致了问题的出现。

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    string str1,str2;
    while(cin>>str1>>str2){
        int stand_len=min(str1.length(),str2.length());
        if(str1.length()>str2.length())
            swap(str1,str2);
        string str_result=" ";
        for(int i=stand_len;i>0 && str_result==" ";i--){
            for(int j=0;j<stand_len-i ;j++){
                 string str_temp=str1.substr(j,i);
                 if(int(str2.find(str_temp))<0)
                     continue;
                 str_result=str_temp; 
                   break;
            }
        }
        cout<<str_result<<endl;
    }
    return 0;
}

64. 配置文件恢复

题目描述 :
输入:
输入说明:
多行字符串,每行字符串一条命令
输出:
执行结果,每条命令输出一行
思路分析:

**这道题,思路不难,但是这道题卡了一段时间,主要是一些小细节没有注意好。一个就是find函数找不到指定字符时,不是返回-1,而是返回一个很大的数。另一个就是输入字符串存在空格,就不能用cin了,而是需要用getline(cin,str)。还有一个就是子串记得要多加一个1,作为最后位置的“\0”。
这个题的思路还是很简单的,一个就是,子串的划分,还有一个就是map类型的应用**

代码:

#include<bits/stdc++.h>
using namespace std;
//建立一个字典,将相应的指令存进去
map<string,string> config_map(){
    map<string,string>config;
    config.insert(pair<string,string>("reset","reset what"));
    config.insert(pair<string,string>("reset board","board fault"));
    config.insert(pair<string,string>("board add","where to add"));
    config.insert(pair<string,string>("board delet","no board at all"));
    config.insert(pair<string,string>("reboot backplane","impossible"));
    config.insert(pair<string,string>("backplane abort","install first"));
    config.insert(pair<string,string>("he he","unkown command"));
    return config;
}
//建立一个将带有空格的字符串拆分成两个字符串的函数
vector<string> split_str(string & str){
    vector<string>input_str;
        if(str.find(" ")>0 && str.find(" ")<100 ){
            input_str.push_back(str.substr(0,str.find(" ")+1));
            input_str.push_back(str.substr(str.find(" ")+1,str.size()-str.find(" ")+1));                    
        }else{
            input_str.push_back(str);
        }
    return input_str;
}
//匹配的子串函数
bool son_str(string str1,string str2){
    if(str2.find(str1)==0)
        return true;
    return false;
}
//进行匹配的函数
bool match_string( string str1,string str2){
    vector<string> split_str1=split_str(str1);
    vector<string> split_str2=split_str(str2);
    //将两个字符串拆分成两个部分,先对比第一个字符,如果第一个字符匹配了,然后就不看第二个匹配了
    //优先对比首字母,然后向后面进行对比
        for(int i=0;i<split_str1.size();i++){
            if(!son_str(split_str1[i],split_str2[i]))
                return false; 
            else
                continue;
    }
    return true;
}
//封装一下match_string函数
void match_file(string str){
    map<string,string> map_list=config_map();
    map<string,string>::iterator iter;
    for(iter=map_list.begin();iter!=map_list.end();iter++){

        if(match_string(str,iter->first)){
            cout<<iter->second<<endl;
            return;
        }
    }   
    cout<<map_list["he he"]<<endl; 
    return;
}
int main(){
    string str;
    while(getline(cin, str)){
        match_file(str);
    }
    return 0;
}

猜你喜欢

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