Acwing第56场周赛+力扣第298场周赛补题

Acwing第56场周赛


第一题:4482. 分组

题目:给定一个长度为n的数组 a1,a2,…,an。请你将这n个元素重新分组,要求每个组内的元素两两不等,且分组数量应尽可能少。请你计算最少所需的分组数量。

分析:要保证每个分组里面没有重复的元素,就要将重复的元素分别放在一个新的组,所以分组的数目即为重复最多的元素重复的次数。我们可以构建一个数组或者哈希表,统计每个元素出现的次数,然后取最大值即可。

代码

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 110;

int n;
int cnt[N];//用于存储元素出现的次数

int main()
{
    cin >> n;
    int res = 0;

    for(int i = 0;i < n; i ++){
        int x;
        cin >> x;
        cnt[x] ++;//x出现的次数加1
        res = max(res,cnt[x]); 
    }
    cout << res << endl;
    return 0;
}

 第二题:4483.格斗场

题目:一个格斗场内有n个战士,其中第i个战士的战斗力为ai。作为格斗场内的经理人,你需要给战士们安排一对一的决斗。这些决斗是一场接一场进行的,一场结束后才会安排下一场。为了保证决斗的观赏性,在安排时需保证:

  • 决斗双方的战斗力不能相同。
  • 决斗双方的战斗力差距不能超过K。

已知,在决斗中战斗力高的选手一定可以将战斗力低的选手击败,并且失败的选手会被赶出格斗场。请你合理安排决斗,使得当剩余选手之间无法再安排任何决斗时,剩余选手的数量越少越好。请你输出剩余选手的最小可能数量。

分析:将n个战士的战斗力从低到高排序,必定是战斗力高的战士来淘汰战斗力低的战士,当且仅当两者战斗力之差大于0小于k时战斗力低的被淘汰。只需在这个有序战斗力数组中找到一个aj使得aj为满足aj-ai>k的最小数,则a(j-1)就是满足条件的最大值。每找到一个满足条件的a(j-1),淘汰人数就增加一个,即存活人数就减一。

代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 200010;

int n, k;
int a[N];

int main()
{
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
    sort(a, a + n);//将战斗力从小到大排序(sort函数无说明时默认从小到大)

    int res = n;//留下的战士数为总人数减去被淘汰的
    for (int i = 0, j = 0; i < n; i ++ )
    {
        while (j < n && a[j] - a[i] <= k) j ++ ;//从前往后找到一个j使得a[j]-a[i] > k就停止循环
        if (a[j - 1] > a[i]) res -- ;//检验此时a[j-1]满足大于a[i]表示a[i]可以被淘汰,存活士兵数减1,接下来进入下一个循环检测战斗力a[i+1]的士兵是否会被淘汰
    }

    printf("%d\n", res);
    return 0;
}

力扣第298场周赛


第一题:5242.兼具大小写的最好英文字母

题目:给你一个由英文字母组成的字符串 s ,请你找出并返回 s 中的 最好 英文字母。返回的字母必须为大写形式。如果不存在满足条件的字母,则返回一个空字符串。最好 英文字母的大写和小写形式必须  在 s 中出现。英文字母 b 比另一个英文字母 a 更好 的前提是:英文字母表中字母b 在字母 a 之  出现。

分析:分别用两个数组存储字符串s中的字母出现大写字母和小写字母的情况,存在则在数组中数值加一,不存在则为0,当且仅当该字母的两个数组都不为0时表示大小写均存在,再转化为大写字母输出。

class Solution {
public:
    string greatestLetter(string s) {
        int m[26];//存放大写字母存在情况
        int n[26];//存放小写字母存在情况
        memset(m, 0, sizeof m);//memset函数把数组m中所有数字换做0,对数组初始化。
        memset(n, 0, sizeof n);
        for(int i = 0; i < s.size(); i ++)
        {
            if(s[i] >= 'A' && s[i] <= 'Z')m[s[i] - 'A'] ++;//如果该字母在大写字母范围内则对应的大写字母标记位加1(因为可能不止出现一次相同大写字母)
            else n[s[i] - 'a'] ++;
        }
        string res;
        for(int i = 0; i < 26; i ++)
        {
            if(m[i] && n[i])res = i + 'A';//当且仅当m[i]和n[i]都为true(0为false)时,将i转化为大写字母并输出
        }
        return res;
    }
};

第二题:2310.个位数字为k的整数之和

题目:给你两个整数 num 和 k ,考虑具有以下属性的正整数多重集:每个整数个位数字都是 k 。
所有整数之和是 num 。返回该多重集的最小大小,如果不存在这样的多重集,返回 -1 。注意:多重集与集合类似,但多重集可以包含多个同一整数,空多重集的和为 0 。个位数字是数字最右边的数位。

分析:多重集中每个满足条件的数可以表示成 10 的倍数加上 k 的形式。由于这 n 个数都以 k 结尾,可得num - nk必须是10的倍数。从小到大枚举得到的最小的n即是我们要找的答案,找到第一个满足 num-nk 是 10 的倍数的 n。而n最大不会超过num。

代码

class Solution {
    public int minimumNumbers(int num, int k) {
        if(num == 0)return 0;//n最小为1,最大不超过num
        for(int n = 1;n <= num && num - n*k >= 0;n ++){
            if((num - n*k)%10 == 0){
                return n;
            }
        }
        return -1;//未找到
    }
};

其中n的上限还可以进行优化:因为num%10=(n*k)%10,而(n*k)%10又可转化为(n%10)*(k%10),当n=11时和n=1时的结果重复,所以n最大可以取到10。即for循环中n<=num可优化为n<=10

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值