Problem Link

Description


You are given a 0-indexed array usageLimits of length n.

Your task is to create groups using numbers from 0 to n - 1, ensuring that each number, i, is used no more than usageLimits[i] times in total across all groups. You must also satisfy the following conditions:

  • Each group must consist of distinct numbers, meaning that no duplicate numbers are allowed within a single group.
  • Each group (except the first one) must have a length strictly greater than the previous group.

Return an integer denoting the maximum number of groups you can create while satisfying these conditions.

 

Example 1:

Input: usageLimits = [1,2,5]
Output: 3
Explanation: In this example, we can use 0 at most once, 1 at most twice, and 2 at most five times.
One way of creating the maximum number of groups while satisfying the conditions is: 
Group 1 contains the number [2].
Group 2 contains the numbers [1,2].
Group 3 contains the numbers [0,1,2]. 
It can be shown that the maximum number of groups is 3. 
So, the output is 3. 

Example 2:

Input: usageLimits = [2,1,2]
Output: 2
Explanation: In this example, we can use 0 at most twice, 1 at most once, and 2 at most twice.
One way of creating the maximum number of groups while satisfying the conditions is:
Group 1 contains the number [0].
Group 2 contains the numbers [1,2].
It can be shown that the maximum number of groups is 2.
So, the output is 2. 

Example 3:

Input: usageLimits = [1,1]
Output: 1
Explanation: In this example, we can use both 0 and 1 at most once.
One way of creating the maximum number of groups while satisfying the conditions is:
Group 1 contains the number [0].
It can be shown that the maximum number of groups is 1.
So, the output is 1. 

 

Constraints:

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

Solution


C++

class Solution {
public:
    int maxIncreasingGroups(std::vector<int>& usageLimits) {
        int N = usageLimits.size();
        sort(usageLimits.rbegin(), usageLimits.rend());
        int left = 0, right = usageLimits.size();
 
        auto good = [&](int k) -> bool {
            vector<int> A = usageLimits;
            int credit = 0;
            
            for (int i = 0; i < N; i++) {
                if (A[i] >= k) {
                    A[i] -= k;
                    
                    if (credit > 0) credit -= A[i];
                } else {
                    credit += k - A[i];
                }
                
                if (k > 0) {
                    k -= 1;
                }
            }
            
            return credit <= 0;
        };
 
        while (left < right) {
            int mid = left + (right - left + 1) / 2;
 
            if (good(mid)) {
                left = mid;
            } else {
                right = mid - 1;
            }
        }
 
        return left;
    }
};
 

Python3

class Solution:
    def maxIncreasingGroups(self, usageLimits: List[int]) -> int:
        N = len(usageLimits)
        usageLimits.sort(reverse = 1)
        left, right = 0, N
        
        def good(k):            
            A = usageLimits[:]
            credit = 0
 
            for x in A:
                if x >= k:
                    x -= k
 
                    if credit > 0:
                        credit -= x
                else:
                    credit += k - x
                
                if k > 0:
                    k -= 1
            
            return credit <= 0
        
        while left < right:
            mid = left + (right - left + 1) // 2
            
            if good(mid):    
                left = mid
            else:
                right = mid - 1
        
        return left