笔试练习day14


感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录
🏀🏀🏀 笔试练习题

乒乓球框

链接
在这里插入图片描述

题目解析

这道题的意思就是B是A的子集,因为要求的是B的种类A也要有,且A的数量还要大于等于B,并且我们可以从题目中知道每个乒乓是用大写字母来表示的,所以我们可以确定最多有26种不同的乒乓
此外这个题目的输入和输出结果有一点问题,
表示的是换行符,实际上的输入和输出是这样的
在这里插入图片描述
我们还需要注意题目中说的是多组数据,但是没具体给一个变量来表示有多少组,所以要用while循环去做

这道题很明显是用哈希表去做,哈希表常用于统计信息再去查找的情况

代码

#include <iostream>
using namespace std;

int main() {
    string s1,s2;
    while(cin>>s1>>s2)
    {
        int hash[26]={0};
        int i=0;
       for(auto ch:s1)hash[ch-'A']++;
       for(auto ch:s2)hash[ch-'A']--;
       for(i=0;i<26;i++)
       {
        if(hash[i]<0)
        {
            cout<<"No"<<endl;
            break;
        }
       }
       if(i==26)
        cout<<"Yes"<<endl;
        i=0;
    }
    return 0;
    }
代码解析

while(cin>>s1>>s2)是判断是否还需要输入,和C语言的while(scanf(“%s”,&ch)!=EOF)一样

之后用范围for去遍历s1和s2

因为总共26个字母,所以我们用 i 去记for循环了多少次,如果i=26说明B是A的子集,如果i<26就说明还没有循环完就退出了,说明B比A多一些不一样的字母,或者相同字母的数量更多一些

组队竞赛

链接
在这里插入图片描述

题目解析

这道题的意思就是每队有3个人,而我们只看中间那个人的水平值,也就是说无论队伍中最高水平的值有多高,最低水平值有多低,都只看中间那个人的水平值,所以我们要让中间那个人的水平值尽可能大,因为不止一队,且最后我们要求的是所以队伍的中间水平值之和,因此要合理安排队伍水平
我们以题目中的例子为例
在这里插入图片描述
因为这个顺序是乱的,我们以从小到大的顺序进行排序
在这里插入图片描述
因为最大值8和最小值1是不可能作为中间值的,所以我们可以直接把1和8去掉
此时就变成这样
在这里插入图片描述
此时最大值是5,假设最右边的最大值不是5,而是6
在这里插入图片描述
如果我们不去选择那个6而是选择5,那么就会编程下面这样
在这里插入图片描述
此时还剩的数字为2 5 6,因为最大值6和最小值2是不可能被作为水平值取到的,所以我们只能选择中间的5
这样的话我们会发现这个6我们就浪费掉了,因为如果不取的话后面就取不到了,因此我们每次取水平值的时候都要取最右边的第二个数字

而怎么快速的取呢,我们可以以从大到小的顺序取找
题目中告诉的n为2,也就是2组,总共有6个人,我们将他们的水平值用数组存起来,通过下标取找
在这里插入图片描述
因为是从最右边的第二个开始取,每次取后他们其实都是隔了一个数字的,因为那个数字是作为最大值被删掉的
在这里插入图片描述
所以我们直接用一个count取记录,每次去完后往左移动2,就行了
此外我刚刚还想到了用递归的方式,但是感觉不是很好,所以就不写了

代码

#include <iostream>
#include<algorithm>
using namespace std;
const long long N = 1e9 + 10;
long long arr[N] = {};

bool cmp(int a, int b) {
    return a < b;
}
int main() {
    int n = 0;
    cin >> n;
    for (int i = 0; i < 3 * n; i++)cin >> arr[i];
    sort(arr, arr + 3 * n, cmp);
    long long count = 0;
    for (int i = 1; i <= n; i++)count += arr[3 * n - 2 * i];
    cout << count << endl;
    return 0;
}

删除相邻数字的最大分数(需要重做)

链接1
链接2
在这里插入图片描述

题目解析

这道题要注意理解题目,题目中有句话是这样说的
在这里插入图片描述
注意是所有等于ai-1和ai+1的元素都删除,我一开始以为是ai左边和右边的元素ai-1和ai+1删除,实际上我理解错了,是值为ai-1和ai+1,另外我后面还把ai-1和ai+1看成了元素的下标,以为是将为ai左边和右边值相等的元素都删除

我们可以用一个hash数组取记录相等的值有多少个
这样就变成了在hash表中选择不相邻的数字,使他们总和最大
在这里插入图片描述
这道题的解法是动态规划
我们可以用f[ i ]表示选到i位置后,i位置元素必选,此时的最大分数
g[ i ]表示选到i位置位置后,i位置元素不选,此时的最大分数
这样我们就可以列出状态转移方程
在这里插入图片描述
当i位置必选的时候,就可以向hash表中取i位置的值,而i-1就必定不可选(题目说明了ai-1要删除),也就是i-1不选时的最大分数,我们是用的g[ i-1]表示的
所以f[ i ]=hash[ i ]+g[ i-1]

因为f[ i ]表示的是i位置必选,但是最后的结果不一定是最大的,所以我们还需要取验证g[ i ]的值是否大于f[ i ]
在这里插入图片描述
在验证g[ i ]时我们需要讨论情况,我们可以不取i-1位置的值,也可以取i-1位置的值,因为题目没有明确说必须要从最大的值开始取,此时我们需要比较f[ i-1 ]和g[ i-1 ]谁最大

初始化g[ 0 ]=0,最后返回f[ n ]和g[ n ]的最大值

代码

const int N = 1e4 + 10;
int sum[N];
int f[N], g[N];
class Solution {
  public:
    int boredom(vector<int>& a) {
        for (vector<int> ::iterator it = a.begin(); it < a.end(); it++) sum[*it]++;
        for (int i = 1; i < N; i++) {
            f[i] = i*sum[i] + g[i - 1];
            g[i] = max(g[i - 1], f[i - 1]);
        }
        return max(g[N - 1], f[N - 1]);
    }
};
代码解析

注意很多人有疑惑为什么是f[i] = isum[i] + g[i - 1],而不是f[i] = i + g[i - 1]
因为我们知道f[ i ]表示的是选择i位置的值这种情况,既然我们选择了i位置的值后,哈希表sum[ i ]的值就应该减减,值到为0,此时i位置的值就取完了,为了方便计算,我们就直接用的 i
sum[i],就省去了sum[i]减减这一步了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值