[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;
}