[TOC]

​ 华为机试题库共103道题目,其中入门级5道,简单级46道,中等级36道,较难级13道,困难级3道。计划在7天内共完成入门级,简单级,中等级的共计87道题目,则每天应当完成13道左右。计划每天完成:

​ 入门级:1道 简单级:7道 中等级:6道

一、入门级

HJ9 提取不重复的整数

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

int main(){
    unordered_map<int,int> dict;// 统计频率
    int num;
    cin>>num;
    //从右向左扫描整数
    for(;0 < num;num /= 10){
        int cur=num%10;// 获取当前位的数字
        // 如果cur的数字为0说明之前没出现过
        if (!dict.count(cur)){
            dict[cur] = 1;//标记
            cout<<cur;
        }
    }
    return 0;
}

二、简单级

1、HJ108 求最小公倍数

#include <bits/stdc++.h>
using namespace std;
/*求2个数的最小公倍数,其一定是2个数中最大数的整数倍
所以遍历的时候可以,最小是2个数中的最大值,最大是2个数的乘积,每次加一个最大数
*/
int main(){
    // 获取输入
    int n1,n2;
    cin>>n1>>n2;
    // 计算两个数的最小公倍数
    int max_v=n1*n2;
    int inin_v=max(n1,n2);// 最小的可能公倍数
    int res=inin_v;
    for(;res<=max_v;res+=inin_v){
        if(res%n1==0&&res%n2==0) break;
    }
    cout<<res;
}

2、HJ56 完全数计算

#include <bits/stdc++.h>
using namespace std;
/*求n以内的完全数,首先1肯定不是,所以遍历到n时应该从2开始
那么如果判断每个i是否是完全数呢?暴力搜索
遍历[2,i/2]中的数,计算除自身以外的约数和
*/
int main(){
    int n;  //待输入的数
    cin>>n;
    int count=0;  //计数器
    //遍历从2到n的每一个数,并在下一层for计算是否为完全数
    for(int i=2;i<=n;i++) 
    {
        int sum=1;  //每个数都包含1这个因数
        // 遍历[2,i/2]中的数,计算除自身以外的约数和
        for(int j=2;j<=i/2;j++) //除以2:根据题干推出的缩小i范围的方法
        {
            if(i%j==0)
                sum=sum+j;
        }
        // 如果约数和==i,说明是完全数
        if(i==sum) count++;
    }
    cout<<count<<endl;
    return 0;
}

3、HJ6 质数因子

#include <bits/stdc++.h>
using namespace std;
/*求一个正整数n的质数因子,首先1肯定不是,所以遍历到n时应该从2开始
正整数中质数有无穷多个。某个数的质因数是有限的,
而且除了最大的质因数,其他质因数的大小不会超过该数开方。
最坏的情况就是总共有两个质因数,每个质因数都是最大质因数,
那么该质因数就达到了上限:原数的开方。
所以解题思路为遍历2到该数开方的数,将原数依次相除,每个数都除到有余数为止;
那么其中非质因数的数相当于不会遍历到。直到最后剩下一个最大质因数或者1。
*/

int main(){
    // 获取输入
    int n;
    cin>>n;
    // n的质数因子的范围[2,sqrt(n)]
    for (int i = 2; i <= sqrt(n); ++i){
        // 如果n可以整除i,那么i就是一个质数因子
        while(n % i == 0){
            cout << i << ' ';
            n = n / i;// i
        }
    }
    if(n != 1)
        cout << n;
    return 0;
}

4、HJ76 尼科彻斯定理

#include <bits/stdc++.h>
using namespace std;
/* 本题是求一个正整数m的m个连续奇数
这m个连续奇数正好是一个等差序列,假设第一个项是i,则第m项是i+*2(m-1)
则连续n个连续奇数和=(i+i+*2(m-1))*m/2=m*m*m
求得 i=m*m-m+1; 则输出得等差序列即可
*/
int main(){
    // 获取输入
    int m;
    cin>>m;
    int i=m*m-m+1;//m个连续奇数的第一个数
    // 输出m个连续奇数
    while(m--){
        if(m==0) cout<<i;//最后一个数后不需要"+"
        else cout<<i<<"+";
        i=i+2;//下一个奇数
    }
    return 0;
}

5、HJ53 杨辉三角的变形

#include<bits/stdc++.h>
using namespace std;
/*本题是一道杨辉三角的找规律题型:
只有n为1,2时,没有出现偶数,剩下的按照2 3 2 4的规律每四行循环一次。
n=1,index=-1
n=2,index=-1
n=3,index=2
n=4,index=3
n=5,index=2
n=6,index=4
n=7,index=2
n=8,index=3
n=9,index=4
n=10,index=2
*/
int main(){
    // 获取输入
    int n;
    cin>>n;
    // 处理
    if(n==1||n==2) cout<<-1<<endl;
    else if(n%4==3) cout<<2<<endl;
    else if(n%4==0) cout<<3<<endl;
    else if(n%4==1) cout<<2<<endl;
    else if(n%4==2) cout<<4<<endl;
    return 0;
}

6、HJ72 百钱买百鸡问题

#include <bits/stdc++.h>
using namespace std;
/* 本题是一道解方程题,答案是唯一的,可以直接输出
但是为了
*/
int main(){
    int n;
    cout<<"0 25 75\n4 18 78\n8 11 81\n12 4 84"<<endl;  
//     for(int i=0;i<=100;i++)
//     {
//         for(int j=0;j<=100-i;j++)
//         {
//             if(5*i+j*3+(100-i-j)/3==100&&(100-i-j)%3==0)
//             {

//                 cout<<i<<" "<<j<<" "<<100-i-j<<endl;
//             }
//         }
//     }
    return 0;
}

7、HJ99 自守数

#include<bits/stdc++.h>
using namespace std;
/*
求自守数的解题思路
规律:个位数为 0、1、5、6 的数才可能是自守数,故采用筛选法,只判断符合该条件的数
思路1:可以把整数(数及其平方)转换为字符串,通过比较长字符串的末尾是否与短字符串相同即可
如:25 * 25 = 625,字符串'625'的末尾'25'与字符串'25'的相同
思路2:若该数的平方与该数的差,去模该数对应的各个进制位均等于零,则该数为自守数
如:25 * 25 = 625,625 - 25 = 600,600 % (10*1) = 0,600 % (10 * 2) = 0
*/
int main(){
    // 获取输入
    int n;
    cin>>n;
    // 递归调用
    int res=0;
    for(int i=0;i<=n;++i){
        //仅对个位数符合条件的数执行自守数的判断(没有该判断也能通过,加上效率更高)
        if((i%10 == 0) || (i%10 == 1) || (i%10 == 5) || (i%10 == 6)){
            long j = i*i;
            string s1=to_string(i);
            string s2=to_string(j);
            int n1=s1.length();
            int n2=s2.length();
            if(s2.substr(n2-n1,n1)==s1) res++;
        }
    }
    cout<<res;
}

8、HJ60 查找组成一个偶数最接近的两个素数

#include<bits/stdc++.h>
using namespace std;
// 判断一个数是否是素数/质数
bool is_prime(int n){
    // 质数:一个大于1的、除了1和自身都不能整除的自然数
    for(int i=2;i<n;i++){
        if(n%i==0) return false;
    }
    return true;
}

int main(){
    // 获取输入
    int n;
    cin>>n;
    // 遍历n的质数因子[2,sqrt(n)]
    int n1=0;
    int n2=0;
    int min_v=n;//最小的差值
    for(int i=sqrt(n);i<=n;i++){
        // 如果i<n-i并且i和n-i都是素数
        if(i<=n-i&&is_prime(i)&&is_prime(n-i)){
            int cur_min=n-i-i;
            if(cur_min<min_v){
                min_v=cur_min;
                n1=i;
                n2=n-i;
            }
        }
    }
    cout<<n1<<endl<<n2<<endl;
    return 0;
}

9、HJ61 放苹果

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

// 把m个苹果放在n个盘子里的分法
int f(int m,int n){
    // 如果只有1个盘子或者苹果数为0,则只有一种分法
    if(m==0 || n==1)
        return 1;
    // 如果n>m,则必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响。即if(n>m) f(m,n) = f(m,m)  
    else if(n>m)
        return f(m,m);
    // 如果n<=m,则盘子数比苹果数少
    else
        /* 存在如下2种情况:
        1、有至少一个盘子空着,则可以拿走这个盘子,即相当于f(m,n) = f(m,n-1);
        2、所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即f(m,n) = f(m-n,n).
        而总的放苹果的放法数目等于两者的和,即 f(m,n) =f(m,n-1)+f(m-n,n)
        */
        return f(m,n-1)+f(m-n,n);// 把m个苹果放在n-1个盘子里的分法
}

int main(){
    // 获取输入
    int m,n;
    cin>>m>>n;
    // 输出结果
    cout << f(m,n) << endl;
}

10、HJ91 走方格的方案数

(1)递归法

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

// f(n,m)表示从[0,0]到[n-1,m-1]的走法数
int f(int n,int m){
    if(n==0||m==0) return 1;// 当处于第一列或第一行时,明显只有一种走法
    return f(n-1,m)+f(n,m-1);
}

int main(){
    // 获取输入
    int n,m;
    cin>>n>>m;
    cout<<f(n,m)<<endl;
    return 0;
}

(2)动态规划法

#include<bits/stdc++.h>
using namespace std;
/* 解析:本类型题是网格路径问题,可以看做是二维版本的爬楼梯问题
    【状态定义】:dp[i][j] 表示的含义为从[0,0]到[i-1,j-1]的走法数
    【转移方程】:[i,j]只能是从上一格[i,j-1]或者左一格[i-1,j]达到
    所以dp[i][j]=dp[i][j-1]+dp[i-1][j];
    */
int main(){
    // 获取输入
    int n,m;
    cin>>n>>m;
    //定义动态数组
    vector<vector<int>> dp(n + 1,vector<int>(m + 1,0)) ;
    for(int i=0;i<=n;i++) dp[i][0]=1;
    for(int i=0;i<=m;i++) dp[0][i]=1;
    // 遍历[1,1]到[n,m]
    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;
}

11、HJ85 最长回文子串

#include<bits/stdc++.h>
#include<cmath>
using namespace std;
// 判断是否是回文子串
bool is_true(string & s){
    int left=0;
    int right=s.length()-1;
    while(left<=right){
        if(s[left++]!=s[right--]) return false; 
    }
    return true; 
}

int main(){
    // 获取输入
    string s;
    getline(cin, s);
    //定义动态数组
    int len=s.length();
    int res=0;
    for(int i=0;i<len;i++){
        for(int j=1;j<len-i+1;j++){
            string str=s.substr(i,j);
            //cout<<str<<endl;
            if(is_true(str)&&res<str.length()) res=str.length();
        }
    }
    cout<<res<<endl;
    return 0;
}