华为机试真题练习汇总(61~70)
华为机试真题练习汇总(61~70)
题目来源:华为机试 - 牛客
标记 * 号的代表有难度的题目。
* HJ61 放苹果
描述
把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?
注意:如果有7个苹果和3个盘子,(5,1,1)和(1,5,1)被视为是同一种分法。
输入描述:
输入两个int整数
输出描述:
输出结果,int型
代码 1:
#include <iostream>
#include <vector>
using namespace std;
int main() {
int m, n;
// m个苹果,n个盘子
cin >> m >> n;
// dp[i,j]: i个苹果放进j个盘子的放法
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
// 初始化
for (int i = 1; i <= n; i++) {
// 0个苹果只有1种分法
dp[0][i] = 1;
}
// 状态转移
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++) {
if (i < j) {
// 苹果数<盘子数,则等于它前一个盘子时的分法
dp[i][j] = dp[i][j - 1];
} else {
// 1. 假设有一个盘子为空,则问题转化为将i个苹果放在j-1个盘子上
// 2. 假设所有盘子都装有苹果,则每个盘子上至少有一个苹果,
// 即最多剩下i-j个苹果,问题转化为将i-j个苹果放到j个盘子上
dp[i][j] = dp[i][j - 1] + dp[i - j][j];
}
}
cout << dp[m][n] << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
代码 2:
#include <iostream>
#include <vector>
using namespace std;
int f(int m, int n) {
if (m < 0 || n < 0)
return 0;
if (m == 1 || n == 1)
return 1;
return f(m, n - 1) + f(m - n, n);
}
int main() {
int m, n;
// m个苹果,n个盘子
cin >> m >> n;
cout << f(m, n) << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
HJ62 查找输入整数二进制中1的个数
描述
输入一个正整数,计算它在二进制下的1的个数。
注意多组输入输出!!!!!!
输入描述:
输入一个整数
输出描述:
计算整数二进制中1的个数
代码:
#include <iostream>
using namespace std;
int bitCount(int x) {
int count = 0;
while (x) {
count += x % 2;
x /= 2;
}
return count;
}
int main()
{
int n;
while (cin >> n)
cout << bitCount(n) << endl;
}
// 64 位输出请用 printf("%lld")
描述
一个 DNA 序列由 A/C/G/T 四个字母的排列组合组成。 G 和 C 的比例(定义为 GC-Ratio )是序列中 G 和 C 两个字母的总的出现次数除以总的字母数目(也就是序列长度)。在基因工程中,这个比例非常重要。因为高的 GC-Ratio 可能是基因的起始点。
给定一个很长的 DNA 序列,以及限定的子串长度 N ,请帮助研究人员在给出的 DNA 序列中从左往右找出 GC-Ratio 最高且长度为 N 的第一个子串。
DNA序列为 ACGT 的子串有: ACG , CG , CGT 等等,但是没有 AGT , CT 等等
输入描述:
输入一个string型基因序列,和int型子串的长度
输出描述:
找出GC比例最高的子串,如果有多个则输出第一个的子串
代码:
#include <iostream>
using namespace std;
int gcCount(string& s) {
int count = 0;
for (char& c : s)
if (c == 'G' || c == 'C')
count++;
return count;
}
int main()
{
string dna;
cin >> dna;
int n;
cin >> n;
int max_gc = 0;
string ans;
for (int i = 0; i <= dna.length() - n; i++) {
string tmp = dna.substr(i, n);
int cur_gc = gcCount(tmp);
if (max_gc < cur_gc) {
max_gc = cur_gc;
ans = tmp;
}
}
cout << ans << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
* HJ64 MP3光标位置
描述
MP3 Player因为屏幕较小,显示歌曲列表的时候每屏只能显示几首歌曲,用户要通过上下键才能浏览所有的歌曲。为了简化处理,假设每屏只能显示4首歌曲,光标初始的位置为第1首歌。
现在要实现通过上下键控制光标移动来浏览歌曲列表,控制逻辑如下:
歌曲总数<=4的时候,不需要翻页,只是挪动光标位置。
光标在第一首歌曲上时,按Up键光标挪到最后一首歌曲;光标在最后一首歌曲时,按Down键光标挪到第一首歌曲。
其他情况下用户按Up键,光标挪到上一首歌曲;用户按Down键,光标挪到下一首歌曲。
- 歌曲总数大于4的时候(以一共有10首歌为例):
特殊翻页:屏幕显示的是第一页(即显示第1 – 4首)时,光标在第一首歌曲上,用户按Up键后,屏幕要显示最后一页(即显示第7-10首歌),同时光标放到最后一首歌上。同样的,屏幕显示最后一页时,光标在最后一首歌曲上,用户按Down键,屏幕要显示第一页,光标挪到第一首歌上。
一般翻页:屏幕显示的不是第一页时,光标在当前屏幕显示的第一首歌曲时,用户按Up键后,屏幕从当前歌曲的上一首开始显示,光标也挪到上一首歌曲。光标当前屏幕的最后一首歌时的Down键处理也类似。
其他情况,不用翻页,只是挪动光标就行。
输入描述:
输入说明:
1 输入歌曲数量
2 输入命令 U或者D
输出描述:
输出说明
1 输出当前列表
2 输出当前选中歌曲
代码:
#include <iostream>
using namespace std;
int main()
{
int n;
string commands;
while (cin >> n >> commands) {
int curSong = 1; // 选中的歌曲
int pageBegin = 1; // 页面的起始
int pageEnd = min(4, n); // 页面的末位置
for (char &c:commands) {
if (c == 'U') {
// 向上移动一格
curSong = (curSong - 1 - 1 + n) % n + 1;
} else if (c == 'D') {
// 向下移动一格
curSong = curSong % n + 1;
}
if (curSong < pageBegin) {
// 如果当前歌曲在窗口前,则将窗口往前移动
pageBegin = curSong;
pageEnd = pageBegin + 3;
} else if (curSong > pageEnd) {
// 如果当前歌曲在窗口后,则将窗口往后移动
pageEnd = curSong;
pageBegin = pageEnd - 3;
}
}
for (int i = pageBegin; i <= pageEnd; i++) {
// 输出当前页面
cout << i << ' ';
}
cout << endl;
cout << curSong << endl; // 输出选中的歌曲
}
return 0;
}
HJ65 查找两个字符串a,b中的最长公共子串
描述
查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。
注:子串的定义:将一个字符串删去前缀和后缀(也可以不删)形成的字符串。请和“子序列”的概念分开!
输入描述:
输入两个字符串
输出描述:
返回重复出现的字符
代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
string s1, s2;
cin >> s1 >> s2;
if (s1.size() > s2.size())
swap(s1, s2);
int len1 = s1.size(), len2 = s2.size();
int start = 0, mx = 0; // 记录结果
// dp[i][j]表示以s1[i]和s2[j]结尾的公共子串的最长长度
vector<vector<int> > dp(len1 + 1, vector<int>(len2 + 1, 0));
// 初始化
for (int i = 0; i <= len1; i++)
dp[i][0] = 0;
for (int j = 0; j <= len2; j++)
dp[0][j] = 0;
// 状态转移
for (int i = 1; i <= len1; i++) {
for (int j = 1; j <= len2; j++) {
if (s1[i - 1] == s2[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = 0;
if (dp[i][j] > mx) {
mx = dp[i][j];
start = i - mx;
} else if (dp[i][j] == mx)
start = min(start, i - mx);
}
}
cout << s1.substr(start, mx) << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
HJ66 配置文件恢复
有6条配置命令,它们执行的结果分别是:
注意:he he不是命令。
为了简化输入,方便用户,以“最短唯一匹配原则”匹配(注:需从首字母开始进行匹配):
1、若只输入一字串,则只匹配一个关键字的命令行。例如输入:r,根据该规则,匹配命令reset,执行结果为:reset what;输入:res,根据该规则,匹配命令reset,执行结果为:reset what;
2、若只输入一字串,但匹配命令有两个关键字,则匹配失败。例如输入:reb,可以找到命令reboot backpalne,但是该命令有两个关键词,所有匹配失败,执行结果为:unknown command
3、若输入两字串,则先匹配第一关键字,如果有匹配,继续匹配第二关键字,如果仍不唯一,匹配失败。
例如输入:r b,找到匹配命令reset board 和 reboot backplane,执行结果为:unknown command。
例如输入:b a,无法确定是命令board add还是backplane abort,匹配失败。
4、若输入两字串,则先匹配第一关键字,如果有匹配,继续匹配第二关键字,如果唯一,匹配成功。例如输入:bo a,确定是命令board add,匹配成功。
5、若输入两字串,第一关键字匹配成功,则匹配第二关键字,若无匹配,失败。例如输入:b addr,无法匹配到相应的命令,所以执行结果为:unknow command。
6、若匹配失败,打印“unknown command”
注意:有多组输入。
输入描述:
多行字符串,每行字符串一条命令
输出描述:
执行结果,每条命令输出一行
代码:
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
const vector<vector<string>> orders = {
{"reset"},
{"reset", "board"},
{"board", "add"},
{"board", "delete"},
{"reboot", "backplane"},
{"backplane", "abort"}
};
const vector<string> executes = {
"reset what",
"board fault",
"where to add",
"no board at all",
"impossible",
"install first"
};
const string uc = "unknown command";
int main() {
string order;
while (getline(cin, order)) { // 输入只有一字串和二字串
int space = count(order.begin(), order.end(), ' ');
if (space == 0) { // 一字串
if (orders[0][0].substr(0, order.length()) == order)
cout << executes[0] << endl;
else
cout << uc << endl;
} else { // 二字串
int space_idx = order.find(' ');
string word1 = order.substr(0, space_idx);
string word2 = order.substr(space_idx + 1);
int macth_cnt = 0; // 匹配个数
string ans;
for (int i = 1; i <= 5; i++) {
if (orders[i][0].substr(0, word1.length()) == word1 &&
orders[i][1].substr(0, word2.length()) == word2) {
macth_cnt++;
ans = executes[i];
}
}
if (macth_cnt == 1)
cout << ans << endl;
else // 匹配结果不唯一,匹配失败
cout << uc << endl;
}
}
return 0;
}
// 64 位输出请用 printf("%lld")
HJ67 24点游戏算法
描述
给出4个1-10的数字,通过加减乘除运算,得到数字为24就算胜利,除法指实数除法运算,运算符仅允许出现在两个数字之间,本题对数字选取顺序无要求,但每个数字仅允许使用一次,且需考虑括号运算
此题允许数字重复,如3 3 4 4为合法输入,此输入一共有两个3,但是每个数字只允许使用一次,则运算过程中两个3都被选取并进行对应的计算操作。
输入描述:
读入4个[1,10]的整数,数字允许重复,测试用例保证无异常数字。
输出描述:
对于每组案例,输出一行表示能否得到24点,能输出true,不能输出false
代码:
#include<iostream>
#include<vector>
using namespace std;
// 暴力
// bool check(vector<double>& nums) {
// char op[4] = {'+', '-', '*', '/'};
// sort(nums.begin(), nums.end()); //先按照从小到大排
// do {
// for (int i = 0; i < 4; i++) //遍历三个位置的所有可能运算符
// for (int j = 0; j < 4; j++)
// for (int k = 0; k < 4; k++) {
// double first = cal(nums[0], nums[1], op[i]); //依次运算
// double second = cal(first, nums[2], op[j]);
// if (cal(second, nums[3], op[k]) == 24) //判断是否等于24
// return true;
// }
// } while (next_permutation(nums.begin(), nums.end())); //依次找到其他排列
// return false;
// }
// 递归检查能否组成24
bool check(vector<double> nums, double result) {
if (nums.empty()) {
// 数组为空,判断等不等于24
return result == 24;
}
// 遍历剩下的数字
for (int i = 0; i < nums.size(); i++) {
vector<double> rest(nums);
rest.erase(rest.begin() + i); // 删去使用的数字
if (check(rest, result + nums[i])
|| check(rest, result - nums[i])
|| check(rest, result * nums[i])
|| check(rest, result / nums[i]))
return true;
}
return false;
}
int main() {
vector<double> nums(4);
for (int i = 0; i < 4; i++)
cin >> nums[i];
if (check(nums, 0))
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
HJ68 成绩排序
描述
给定一些同学的信息(名字,成绩)序列,请你将他们的信息按照成绩从高到低或从低到高的排列,相同成绩
都按先录入排列在前的规则处理。
示例:
jack 70
peter 96
Tom 70
smith 67
从高到低 成绩
peter 96
jack 70
Tom 70
smith 67
从低到高
smith 67
jack 70
Tom 70
peter 96
注:0代表从高到低,1代表从低到高
输入描述:
第一行输入要排序的人的个数n,第二行输入一个整数表示排序的方式,之后n行分别输入他们的名字和成绩,以一个空格隔开
输出描述:
按照指定方式输出名字和成绩,名字和成绩之间以一个空格隔开
代码:
#include <iostream>
#include <map>
#include <vector>
using namespace std;
int main() {
int n;
int flag;
cin >> n >> flag;
map<int, vector<string>> mp;
for (int i = 0; i < n; i++) {
string name;
int score;
cin >> name >> score;
mp[score].push_back(name);
}
if (flag == 0) { // 从高到低
for (auto it = mp.rbegin(); it != mp.rend(); ++it) {
// 逆序遍历
for (int i = 0; i < it->second.size(); i++)
cout << it->second[i] << " " << it->first << endl;
}
} else { // 从低到高
for (auto it = mp.begin(); it != mp.end(); ++it) {
// 顺序遍历
for (int i = 0; i < it->second.size(); i++)
cout << it->second[i] << " " << it->first << endl;
}
}
return 0;
}
// 64 位输出请用 printf("%lld")
HJ69 矩阵乘法
描述
如果A是个x行y列的矩阵,B是个y行z列的矩阵,把A和B相乘,其结果将是另一个x行z列的矩阵C。
输入描述:
第一行包含一个正整数x,代表第一个矩阵的行数
第二行包含一个正整数y,代表第一个矩阵的列数和第二个矩阵的行数
第三行包含一个正整数z,代表第二个矩阵的列数
之后x行,每行y个整数,代表第一个矩阵的值
之后y行,每行z个整数,代表第二个矩阵的值
输出描述:
对于每组输入数据,输出x行,每行z个整数,代表两个矩阵相乘的结果
代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
int x, y, z;
cin >> x >> y >> z;
int r1 = x, c1 = y;
int r2 = y, c2 = z;
vector<vector<int>> g1(r1, vector<int>(c1));
vector<vector<int>> g2(r2, vector<int>(c2));
for (int i = 0; i < r1; i++)
for (int j = 0; j < c1; j++)
cin >> g1[i][j];
for (int i = 0; i < r2; i++)
for (int j = 0; j < c2; j++)
cin >> g2[i][j];
vector<vector<int>> ans(r1, vector<int>(c2));
for (int i = 0; i < r1; i++) {
for (int j = 0; j < c2; j++) {
int sum = 0;
for (int k = 0; k < y; k++)
sum += g1[i][k] * g2[k][j];
ans[i][j] = sum;
cout<<ans[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
// 64 位输出请用 printf("%lld")
HJ70 矩阵乘法计算量估算
描述
矩阵乘法的运算量与矩阵乘法的顺序强相关。
例如:
A是一个50×10的矩阵,B是10×20的矩阵,C是20×5的矩阵
计算ABC有两种顺序:((AB)C)或者(A(BC)),前者需要计算15000次乘法,后者只需要3500次。
编写程序计算不同的计算顺序需要进行的乘法次数。
输入描述:
输入多行,先输入要计算乘法的矩阵个数n,每个矩阵的行数,列数,总共2n的数,最后输入要计算的法则
计算的法则为一个字符串,仅由左右括号和大写字母(‘A’~‘Z’)组成,保证括号是匹配的且输入合法!
输出描述:
输出需要进行的乘法次数
代码:
#include <iostream>
#include <stack>
#include <utility>
#include <vector>
using namespace std;
int main() {
int n;
cin >> n;
vector<pair<int, int>> gv;
for (int i = 0; i < n; i++) {
int r, c;
cin >> r >> c;
gv.push_back(make_pair(r, c));
}
string s;
cin >> s;
int sum = 0;
stack<pair<int, int>> gs;
for (char& c : s) {
if (c == ')') {
pair<int, int> g2 = gs.top();
gs.pop();
pair<int, int> g1 = gs.top();
gs.pop();
int r1 = g1.first, c1 = g1.second;
int r2 = g2.first, c2 = g2.second;
if (c1 == r2) {
sum += r1 * c1 * c2;
gs.push(make_pair(r1, c2));
} else if (r1 == c2) {
sum += r1 * c1 * r2;
gs.push(make_pair(c1, r2));
}
} else if (c != '(') {
int idx = c - 'A';
gs.push(gv[idx]);
}
}
cout << sum << endl;
return 0;
}
// 64 位输出请用 printf("%lld")