华为机试真题练习汇总(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键,光标挪到下一首歌曲。

  1. 歌曲总数大于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")
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值