华为机试真题练习汇总(21~30)
华为机试真题练习汇总(21~30)
题目来源:华为机试 - 牛客
标记 * 号的代表有难度的题目。
HJ21 简单密码
描述
现在有一种密码变换算法。
九键手机键盘上的数字与字母的对应: 1–1, abc–2, def–3, ghi–4, jkl–5, mno–6, pqrs–7, tuv–8 wxyz–9, 0–0,把密码中出现的小写字母都变成九键键盘对应的数字,如:a 变成 2,x 变成 9.
而密码中出现的大写字母则变成小写之后往后移一位,如:X ,先变成小写,再往后移一位,变成了 y ,例外:Z 往后移是 a 。
数字和其它的符号都不做变换。
输入描述:
输入一组密码,长度不超过100个字符。
输出描述:
输出密码变换后的字符串
代码:
#include <iostream>
using namespace std;
string pwd_change(string& s) {
for (char& ch : s) {
if (islower(ch)) {
switch (ch) {
case 'a':
case 'b':
case 'c':
ch = '2';
break;
case 'd':
case 'e':
case 'f':
ch = '3';
break;
case 'g':
case 'h':
case 'i':
ch = '4';
break;
case 'j':
case 'k':
case 'l':
ch = '5';
break;
case 'm':
case 'n':
case 'o':
ch = '6';
break;
case 'p':
case 'q':
case 'r':
case 's':
ch = '7';
break;
case 't':
case 'u':
case 'v':
ch = '8';
break;
case 'w':
case 'x':
case 'y':
case 'z':
ch = '9';
break;
}
} else if (isupper(ch)) {
ch = (ch - 'A' + 1) % 26 + 'a';
}
}
return s;
}
int main()
{
string pwd;
cin >> pwd;
cout << pwd_change(pwd) << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
HJ22 汽水瓶
描述
某商店规定:三个空汽水瓶可以换一瓶汽水,允许向老板借空汽水瓶(但是必须要归还)。
小张手上有n个空汽水瓶,她想知道自己最多可以喝到多少瓶汽水。
注意:本题存在多组输入。输入的 0 表示输入结束,并不用输出结果。
输入描述:
输入文件最多包含 10 组测试数据,每个数据占一行,仅包含一个正整数 n( 1<=n<=100 ),表示小张手上的空汽水瓶数。n=0 表示输入结束,你的程序不应当处理这一行。
输出描述:
对于每组测试数据,输出一行,表示最多可以喝的汽水瓶数。如果一瓶也喝不到,输出0。
代码:
#include <iostream>
using namespace std;
int main() {
int n;
while (cin >> n && n) {
int drink = 0;
while (n >= 3) {
drink += n / 3;
n = n % 3 + n / 3;
}
if (n == 2)
drink++;
cout << drink << endl;
}
return 0;
}
// 64 位输出请用 printf("%lld")
HJ23 删除字符串中出现次数最少的字符
描述
实现删除字符串中出现次数最少的字符,若出现次数最少的字符有多个,则把出现次数最少的字符都删除。输出删除这些单词后的字符串,字符串中其它字符保持原来的顺序。
输入描述:
字符串只包含小写英文字母, 不考虑非法输入,输入的字符串长度小于等于20个字节。
输出描述:
删除字符串中出现次数最少的字符后的字符串。
代码:
#include <climits>
#include <iostream>
#include <unordered_map>
using namespace std;
int main()
{
string s;
cin >> s;
unordered_map<char, int> cnt;
for (char& c : s)
cnt[c]++;
int min_cnt = INT_MAX;
for (auto &[ch, count] : cnt)
min_cnt = min(min_cnt, count);
string ans;
for (char& c : s)
if (cnt[c] != min_cnt)
ans += c;
cout << ans << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
* HJ24 合唱队
代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n ;
cin >> n;
vector<int> heights;
for (int i = 0; i < n; i++) {
int h;
cin >> h;
heights.push_back(h);
}
// 最长递增子序列
vector<int> dp1(n, 0);
for (int i = 0; i < n; i++) {
dp1[i] = 1;
for (int j = 0; j < i; j++)
if (heights[i] > heights[j])
dp1[i] = max(dp1[i], dp1[j] + 1);
}
// 最长递减子序列
vector<int> dp2(n, 0);
for (int i = n - 1; i >= 0; i--) {
dp2[i] = 1;
for (int j = n - 1; j > i; j--)
if (heights[i] > heights[j])
dp2[i] = max(dp2[i], dp2[j] + 1);
}
int maxlen = 0;
for (int i = 0; i < n; i++) {
int len = dp1[i] + dp2[i] - 1;
maxlen = max(maxlen, len);
}
cout << n - maxlen << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
* HJ25 数据分类处理
描述
信息社会,有海量的数据需要分析处理,比如公安局分析身份证号码、 QQ 用户、手机号码、银行帐号等信息及活动记录。
采集输入大数据和分类规则,通过大数据分类处理程序,将大数据分类输出。
输入描述:
一组输入整数序列I和一组规则整数序列R,I和R序列的第一个整数为序列的个数(个数不包含第一个整数);整数范围为0~(231)-1,序列个数不限
输出描述:
从R依次中取出R,对I进行处理,找到满足条件的I:
I整数对应的数字需要连续包含R对应的数字。比如R为23,I为231,那么I包含了R,条件满足 。
按R从小到大的顺序:
(1)先输出R;
(2)再输出满足条件的I的个数;
(3)然后输出满足条件的I在I序列中的位置索引(从0开始);
(4)最后再输出I。
附加条件:
(1)R需要从小到大排序。相同的R只需要输出索引小的以及满足条件的I,索引大的需要过滤掉
(2)如果没有满足条件的I,对应的R不用输出
(3)最后需要在输出序列的第一个整数位置记录后续整数序列的个数(不包含“个数”本身)
代码:
#include <algorithm>
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
int main() {
int n, m, num;
vector<int> I, R;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> num;
I.push_back(num);
}
cin >> m;
for (int i = 0; i < m; i++) {
cin >> num;
R.push_back(num);
}
sort(R.begin(), R.end());
vector<int> res;
for (int i = 0; i < m; i++) {
if (i && R[i] == R[i - 1])
continue;
// 满足条件的I的个数
int count = 0;
// 满足条件的I在I序列中的位置索引
vector<int> index;
for (int j = 0; j < n; j++)
if (to_string(I[j]).find(to_string(R[i])) != string::npos) {
count++;
index.push_back(j);
}
if (count) {
res.push_back(R[i]);
res.push_back(count);
for (int& idx : index) {
res.push_back(idx);
res.push_back(I[idx]);
}
}
}
// 先输出后续整数序列的个数
cout << res.size();
for (int& x : res)
cout << " " << x;
cout << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
* HJ26 字符串排序
描述
编写一个程序,将输入字符串中的字符按如下规则排序。
规则 1 :英文字母从 A 到 Z 排列,不区分大小写。
如,输入: Type 输出: epTy
规则 2 :同一个英文字母的大小写同时存在时,按照输入顺序排列。
如,输入: BabA 输出: aABb
规则 3 :非英文字母的其它字符保持原来的位置。
如,输入: By?e 输出: Be?y
输入描述:
输入字符串
输出描述:
输出字符串
代码:
#include <cctype>
#include <iostream>
#include <vector>
using namespace std;
int main() {
string s;
getline(cin, s);
vector<char> alpha;
for (int i = 0; i < 26; i++)
for (char& c : s)
if (c - 'a' == i || c - 'A' == i)
alpha.push_back(c);
int idx = 0;
for (char& c : s)
if (isalpha(c)) {
c = alpha[idx];
idx++;
}
cout << s << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
HJ27 查找兄弟单词
描述
定义一个单词的“兄弟单词”为:交换该单词字母顺序(注:可以交换任意次),而不添加、删除、修改原有的字母就能生成的单词。
兄弟单词要求和原来的单词不同。例如: ab 和 ba 是兄弟单词。 ab 和 ab 则不是兄弟单词。
现在给定你 n 个单词,另外再给你一个单词 x ,让你寻找 x 的兄弟单词里,按字典序排列后的第 k 个单词是什么?
注意:字典中可能有重复单词。
输入描述:
输入只有一行。 先输入字典中单词的个数n,再输入n个单词作为字典单词。 然后输入一个单词x 最后后输入一个整数k
输出描述:
第一行输出查找到x的兄弟单词的个数m 第二行输出查找到的按照字典顺序排序后的第k个兄弟单词,没有符合第k个的话则不用输出。
代码:
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
using namespace std;
bool isBrother(string s1, string s2) {
if (s1.length() != s2.length())
return false;
if (s1 == s2)
return false;
sort(s1.begin(), s1.end());
sort(s2.begin(), s2.end());
return s1 == s2;
}
int main() {
int n;
cin >> n;
vector<string> strDict;
string word;
for (int i = 0; i < n; i++) {
cin >> word;
strDict.push_back(word);
}
string x;
cin >> x;
int k;
cin >> k;
vector<string> brothers;
for (string& s : strDict)
if (isBrother(s, x))
brothers.push_back(s);
cout << brothers.size() << endl;
if (brothers.size() >= k) {
sort(brothers.begin(), brothers.end());
cout << brothers[k - 1] << endl;
}
return 0;
}
// 64 位输出请用 printf("%lld")
** HJ28 素数伴侣
描述
若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,它们能应用于通信加密。现在密码学会请你设计一个程序,从已有的 N ( N 为偶数)个正整数中挑选出若干对组成“素数伴侣”,挑选方案多种多样,例如有4个正整数:2,5,6,13,如果将5和6分为一组中只能得到一组“素数伴侣”,而将2和5、6和13编组将得到两组“素数伴侣”,能组成“素数伴侣”最多的方案称为“最佳方案”,当然密码学会希望你寻找出“最佳方案”。
输入:
有一个正偶数 n ,表示待挑选的自然数的个数。后面给出 n 个具体的数字。
输出:
输出一个整数 K ,表示你求得的“最佳方案”组成“素数伴侣”的对数。
代码:
#include <iostream>
#include <vector>
using namespace std;
bool isprime(int num) {
for (int i = 2; i * i <= num; i++) {
if (num % i == 0)
return false;
}
return true;
}
bool find(int num, vector<int>& evens, vector<bool>& used, vector<int>& match) {
// 遍历每个偶数与奇数比较
for (int i = 0; i < evens.size(); i++) {
if (isprime(num + evens[i]) && !used[i]) {
used[i] = true;
if (match[i] == 0 || find(match[i], evens, used, match)) {
// 如果第i个偶数还未配对,或者跟它配对的奇数还有别的选择
match[i] = num; // 则配对该数
return true;
}
}
}
return false;
}
int main() {
int n;
cin >> n;
vector<int> nums(n);
vector<int> odd; // 奇数
vector<int> even; // 偶数
for (int i = 0; i < n; i++) {
cin >> nums[i];
if (nums[i] % 2)
odd.push_back(nums[i]);
else
even.push_back(nums[i]);
}
// 特判
if (odd.empty() || even.empty()) {
cout << 0 << endl;
return 0;
}
int count = 0;
vector<int> match(even.size(), 0); // 统计每个偶数的配对是哪个奇数
// 遍历每个奇数
for (int i = 0; i < odd.size(); i++) {
vector<bool> used(even.size(), false); // 每一轮偶数都没用过
// 能否找到配对的偶数,且要最优
if (find(odd[i], even, used, match))
count++;
}
cout << count << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
HJ29 字符串加解密
描述
对输入的字符串进行加解密,并输出。
加密方法为:
当内容是英文字母时则用该英文字母的后一个字母替换,同时字母变换大小写,如字母a时则替换为B;字母Z时则替换为a;
当内容是数字时则把该数字加1,如0替换1,1替换2,9替换0;
其他字符不做变化。
解密方法为加密的逆过程。
输入描述:
第一行输入一串要加密的密码
第二行输入一串加过密的密码
输出描述:
第一行输出加密后的字符
第二行输出解密后的字符
代码:
#include <cctype>
#include <iostream>
using namespace std;
string encrypt(string& s) {
for (char& c : s) {
if (isalpha(c)) {
if (islower(c))
c = (c - 'a' + 1) % 26 + 'A';
else
c = (c - 'A' + 1) % 26 + 'a';
} else if (isdigit(c))
c = (c - '0' + 1) % 10 + '0';
}
return s;
}
string decrypt(string& s) {
for (char& c : s) {
if (isalpha(c)) {
if (islower(c))
c = (c - 'a' + 25) % 26 + 'A';
else
c = (c - 'A' + 25) % 26 + 'a';
} else if (isdigit(c))
c = (c - '0' + 9) % 10 + '0';
}
return s;
}
int main() {
string s1;
cin >> s1;
cout << encrypt(s1) << endl;
string s2;
cin >> s2;
cout << decrypt(s2) << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
HJ30 字符串合并处理
描述
按照指定规则对输入的字符串进行处理。
详细描述:
第一步:将输入的两个字符串str1和str2进行前后合并。如给定字符串 “dec” 和字符串 “fab” , 合并后生成的字符串为 “decfab”
第二步:对合并后的字符串进行排序,要求为:下标为奇数的字符和下标为偶数的字符分别从小到大排序。这里的下标的意思是字符在字符串中的位置。注意排序后在新串中仍需要保持原来的奇偶性。例如刚刚得到的字符串“decfab”,分别对下标为偶数的字符’d’、‘c’、‘a’和下标为奇数的字符’e’、‘f’、'b’进行排序(生成 ‘a’、‘c’、‘d’ 和 ‘b’ 、‘e’ 、‘f’),再依次分别放回原串中的偶数位和奇数位,新字符串变为“abcedf”
第三步:对排序后的字符串中的’0’‘9’、‘A’‘F’和’a’~'f’字符,需要进行转换操作。
转换规则如下:
对以上需要进行转换的字符所代表的十六进制用二进制表示并倒序,然后再转换成对应的十六进制大写字符(注:字符 a~f 的十六进制对应十进制的10~15,大写同理)。
如字符 ‘4’,其二进制为 0100 ,则翻转后为 0010 ,也就是 2 。转换后的字符为 ‘2’。
如字符 ‘7’,其二进制为 0111 ,则翻转后为 1110 ,对应的十进制是14,转换为十六进制的大写字母为 ‘E’。
如字符 ‘C’,代表的十进制是 12 ,其二进制为 1100 ,则翻转后为 0011,也就是3。转换后的字符是 ‘3’。
根据这个转换规则,由第二步生成的字符串 “abcedf” 转换后会生成字符串 “5D37BF”。
输入描述:
样例输入两个字符串,用空格隔开。
输出描述:
输出转化后的结果。
代码 1:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <vector>
using namespace std;
int main() {
string str1, str2;
cin >> str1 >> str2;
// 第一步:将输入的两个字符串str1和str2进行前后合并
string out = str1 + str2;
// 第二步:对合并后的字符串进行排序,
// 要求为:下标为奇数的字符和下标为偶数的字符分别从小到大排序
vector<char> odd, even;
for (int i = 0; i < out.length(); i++) {
if (i % 2)
odd.push_back(out[i]);
else
even.push_back(out[i]);
}
sort(odd.begin(), odd.end());
sort(even.begin(), even.end());
int odd_idx = 0, even_idx = 0;
for (int i = 0; i < out.length(); i++) {
if (i % 2)
out[i] = odd[odd_idx++];
else
out[i] = even[even_idx++];
}
// 第三步:对排序后的字符串中的'0'~'9'、'A'~'F'和'a'~'f'字符,需要进行转换操作
const string trans = "084C2A6E195D3B7F";
for (char& c : out) {
if (isdigit(c))
c = trans[c - '0'];
else if (c >= 'A' && c <= 'F')
c = trans[c - 'A' + 10];
else if (c >= 'a' && c <= 'f')
c = trans[c - 'a' + 10];
}
cout << out << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
代码 2:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int reverseDec(int& num) {
vector<int> numBin;
while (num > 1) {
numBin.push_back(num % 2);
num /= 2;
}
numBin.push_back(num);
while (numBin.size() < 4) {
numBin.push_back(0);
}
int retVal = 0;
for (int i = 0; i < numBin.size(); i++) {
retVal += numBin[numBin.size() - 1 - i] * pow(2, i);
}
return retVal;
}
void transform(char& c) {
int numDec;
if (isdigit(c)) {
numDec = c - '0';
} else if (c >= 'A' && c <= 'F') {
numDec = 10 + c - 'A';
} else if (c >= 'a' && c <= 'f') {
numDec = 10 + c - 'a';
}
numDec = reverseDec(numDec);
if (numDec <= 9) {
c = '0' + numDec;
} else {
c = numDec - 10 + 'A';
}
}
int main() {
string str1, str2;
cin >> str1 >> str2;
// 第一步:将输入的两个字符串str1和str2进行前后合并
string out = str1 + str2;
// 第二步:对合并后的字符串进行排序,
// 要求为:下标为奇数的字符和下标为偶数的字符分别从小到大排序
vector<char> odd, even;
for (int i = 0; i < out.length(); i++) {
if (i % 2)
odd.push_back(out[i]);
else
even.push_back(out[i]);
}
sort(odd.begin(), odd.end());
sort(even.begin(), even.end());
int odd_idx = 0, even_idx = 0;
for (int i = 0; i < out.length(); i++) {
if (i % 2)
out[i] = odd[odd_idx++];
else
out[i] = even[even_idx++];
}
// 第三步:对排序后的字符串中的'0'~'9'、'A'~'F'和'a'~'f'字符,需要进行转换操作
const string trans = "084C2A6E195D3B7F";
for (char& c : out) {
if (isdigit(c) || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f')
transform(c);
}
cout << out << endl;
return 0;
}
// 64 位输出请用 printf("%lld")