力扣100097. 合法分组的最少组数(哈希+贪心)

简介: 力扣100097. 合法分组的最少组数(哈希+贪心)

题目描述:

给你一个长度为 n 下标从 0 开始的整数数组 nums

我们想将下标进行分组,使得 [0, n - 1] 内所有下标 i恰好 被分到其中一组。

如果以下条件成立,我们说这个分组方案是合法的:

  • 对于每个组 g ,同一组内所有下标在 nums 中对应的数值都相等。
  • 对于任意两个组 g1g2 ,两个组中 下标数量差值不超过 1

请你返回一个整数,表示得到一个合法分组方案的 最少 组数。

示例 1:

输入:nums = [3,2,3,2,3]

输出:2

解释:一个得到 2 个分组的方案如下,中括号内的数字都是下标:

组 1 -> [0,2,4]

组 2 -> [1,3]

所有下标都只属于一个组。

组 1 中,nums[0] == nums[2] == nums[4] ,所有下标对应的数值都相等。

组 2 中,nums[1] == nums[3] ,所有下标对应的数值都相等。

组 1 中下标数目为 3 ,组 2 中下标数目为 2 。

两者之差不超过 1 。

无法得到一个小于 2 组的答案,因为如果只有 1 组,组内所有下标对应的数值都要相等。

所以答案为 2 。

示例 2:

输入:nums = [10,10,10,3,1,1]

输出:4

解释:一个得到 2 个分组的方案如下,中括号内的数字都是下标:

组 1 -> [0]

组 2 -> [1,2]

组 3 -> [3]

组 4 -> [4,5]

分组方案满足题目要求的两个条件。

无法得到一个小于 4 组的答案。

所以答案为 4 。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109

思路:

题目要求我们求出最小的分组数目,首先我们可以确定的是,一个数组一定有答案,因为再不济把他每个元素都分一个组就可以了,又由于对于任意两个组 g1g2 ,两个组中 下标数量差值不超过1,假设我们分的所有的组的下标数量最小为k,那么最大也只能是k+1.

我们可以先用一个map存下每一个数出现的次数,对于每一个数it,出现的次数为cnt,我们看能否将这cnt个it分为只包含k个和k+1个的组。

假设数组中出现的最小次数的数目为mi,那么很容易得到k<=mi.如果k>mi,意味着至少有一组凑不够k个相同的数(同一组内所有下标在 nums 中对应的数值),所以我们可以遍历k(分的所有的组的下标数量最小值),k确定了,k+1也就确定了。

对于每一个k,我们看nums里的所有数出现的次数能不能分为只包含k个和k+1个的组。

如果可以,我们就把当前k可以分得的最小组的数目求一个最小值ans.

如果不能那就。。。那就不能。

时间复杂读为什么是O(n)?

假设t表示的是nums数组中不同元素的个数,那么最小出现次数mi<=n/t,所以mi*t<=n.

O(min(mp[nums[i])*t)=O(mi*t)=O(n/t *t)=O(n)

这里计算时间复杂度非常重要哦,我开始也是算错了时间复杂度以为是o(n^2)了。、

代码:

class Solution {
public:
    int minGroupsForValidAssignment(vector<int>& nums) {
        map<int,int> mp;
        int len=nums.size();
        int mi=1e9+10;//最少出现次数
        for(auto it:nums){
            mp[it]++;//记录每个元素出现的次数
        }
        for(auto it:mp){
            mi=min(it.second,mi);
        }
        int ans=1e9;
        for(int k=1;k<=mi;k++){
            int tn=0;//记录当前k可以分得到的最小数目的组数
            int f=1;
            for(auto it:mp){
                int cnt=it.second;
                int a = cnt / (k + 1);
                int b = cnt - a * (k + 1);
                if (cnt % (k + 1) == 0) {//尽量拼元素多的组
                    tn += a;
                }
                else if (a + b >= k){//看能不能在a个(k+1)的组里面分诺干个1到剩下的b里面
                     tn += a + 1;
                }else{//优先拼k+1组失败了,退而求其次优先考虑拼k组
                     int a = cnt / (k );
                     int b = cnt - a * (k);
                     if(b>a){//如果剩下的元素b不能分到a个(k)组里面,说明分组失败
                         f=0;
                         break;
                     }
                     tn+=a;
                }
            }
           if(f) ans=min(ans,tn);
        }
 
        return ans;
    }
};


相关文章
|
7月前
leetcode-6133:分组的最大数量
leetcode-6133:分组的最大数量
57 0
|
7月前
|
Go
golang力扣leetcode 49.字母异位词分组
golang力扣leetcode 49.字母异位词分组
37 0
LeetCode题解-让所有学生保持开心的分组方法数
LeetCode题解-让所有学生保持开心的分组方法数
|
4月前
|
存储 算法
LeetCode第49题字母异位词分组
LeetCode第49题"字母异位词分组"的解题方法,通过将每个字符串的字符排序后作为键存储在HashMap中,有效地将所有字母异位词分组。
LeetCode第49题字母异位词分组
|
2月前
|
存储
Leetcode第49题(字母异位词分组)
LeetCode第49题要求将字符串数组中的字母异位词分组,可以通过将每个字符串排序后作为键存入哈希表,最后将哈希表中的值添加到结果列表中来实现。
18 1
|
6月前
|
存储 算法 安全
LeetCode 题目 49:字母异位词分组 5种算法实现与典型应用案例【python】
LeetCode 题目 49:字母异位词分组 5种算法实现与典型应用案例【python】
|
6月前
|
存储
力扣经典150题第四十二题:字母异位词分组
力扣经典150题第四十二题:字母异位词分组
40 0
|
7月前
leetcode热题100. 字母异位词分组
leetcode热题100. 字母异位词分组
48 0
|
7月前
leetcode-49:字母异位词分组
leetcode-49:字母异位词分组
51 0
|
算法 程序员
力扣刷题-字母异位词分组
力扣刷题-字母异位词分组