Maximum Number of Groups Entering a Competition
MedPrompt
You are given a positive integer array grades which represents the grades of students in a university. You would like to enter all these students into a competition in ordered non-empty groups, such that the ordering meets the following conditions:
- The sum of the grades of students in the
ithgroup is less than the sum of the grades of students in the(i + 1)thgroup, for all groups (except the last). - The total number of students in the
ithgroup is less than the total number of students in the(i + 1)thgroup, for all groups (except the last).
Return the maximum number of groups that can be formed.
Example 1:
Input: grades = [10,6,12,7,3,5]
Output: 3
Explanation: The following is a possible way to form 3 groups of students:
- 1st group has the students with grades = [12]. Sum of grades: 12. Student count: 1
- 2nd group has the students with grades = [6,7]. Sum of grades: 6 + 7 = 13. Student count: 2
- 3rd group has the students with grades = [10,3,5]. Sum of grades: 10 + 3 + 5 = 18. Student count: 3
It can be shown that it is not possible to form more than 3 groups.Example 2:
Input: grades = [8,8]
Output: 1
Explanation: We can only form 1 group, since forming 2 groups would lead to an equal number of students in both groups.
Constraints:
1 <= grades.length <= 1051 <= grades[i] <= 105
Approaches
4 approaches with complexity analysis and trade-offs.
This approach is based on the intuition that to satisfy the sum condition (sum_i < sum_{i+1}), we should assign students with lower grades to earlier groups and students with higher grades to later groups. By sorting the grades array first, we can guarantee that if we form groups with increasing sizes (count_i < count_{i+1}), the sum condition will also be met. After sorting, we can greedily determine the number of groups.
Algorithm
- Get the total number of students,
n, from the length of thegradesarray. - Sort the
gradesarray in non-decreasing order. This step ensures that if we form groups with increasing sizes, the sum of grades will also be strictly increasing. - Initialize
k = 0(number of groups) andstudentsUsed = 0. - Iterate with
nextGroupSizestarting from 1. - In each step, check if we have enough remaining students to form a group of this size, i.e., if
studentsUsed + nextGroupSize <= n. - If we do, it means we can form another group. Increment
k, addnextGroupSizetostudentsUsed, and incrementnextGroupSizefor the next iteration. - If not, we don't have enough students, so we stop.
- Return
kas the maximum number of groups.
Walkthrough
The core idea is that if we sort the grades in non-decreasing order, any group formed from consecutive students will have a smaller sum than the next group of a larger size formed from the subsequent students. This is because the later group will have more students, and each of its students will have a grade greater than or equal to any student in the previous group.
The algorithm proceeds as follows:
- Sort the
gradesarray. - Greedily form groups of increasing size: 1, 2, 3, and so on.
- We keep track of the number of students used. We start by forming a group of size 1, then size 2, and so on, as long as we have enough students remaining.
- The total number of groups we can form this way is the maximum possible.
The sorting step is the bottleneck, making this approach less efficient than others that realize the grade values are irrelevant.
import java.util.Arrays; class Solution { public int maximumGroups(int[] grades) { int n = grades.length; // Sorting is done to satisfy the sum condition easily, but as we'll see // in other approaches, it's not strictly necessary to solve the problem. Arrays.sort(grades); int k = 0; // number of groups int studentsUsed = 0; int nextGroupSize = 1; while (studentsUsed + nextGroupSize <= n) { studentsUsed += nextGroupSize; k++; nextGroupSize++; } return k; }}Complexity
Time
O(n log n), dominated by the sorting of the `grades` array. The subsequent loop runs `O(sqrt(n))` times, which is less significant.
Space
O(log n) or O(n), depending on the space used by the sorting algorithm's implementation (e.g., for recursion stack or temporary arrays).
Trade-offs
Pros
Conceptually simple and directly models the problem constraints after sorting.
Guaranteed to be correct.
Cons
Highly inefficient due to the unnecessary sorting step, which has a time complexity of
O(n log n).The core logic of the problem does not depend on the actual grade values, making the sorting redundant.
This approach realizes that the actual values of the grades do not matter, only the total number of students. The conditions on group sums can always be satisfied by sorting the grades and assigning the smallest ones to the first groups. Therefore, the problem reduces to a mathematical puzzle: find the maximum number of groups k such that we can partition n students into groups of strictly increasing sizes. To maximize k, we should use the smallest possible sizes: 1, 2, 3, ..., k.
Algorithm
- Get the total number of students,
n. - Initialize
k = 0(number of groups) andgroupSize = 1. - Loop as long as the remaining students
nare enough to form the next group of sizegroupSize. - Inside the loop, subtract
groupSizefromnto account for the students used. - Increment the group count
k. - Increment
groupSizefor the next iteration. - When the loop terminates,
kholds the maximum number of groups. Returnk.
Walkthrough
The problem is to find the largest integer k such that the sum of the first k positive integers is less than or equal to the total number of students n. That is, 1 + 2 + ... + k <= n.
We can simulate this process iteratively. We start with k=0 groups and n students. In each step, we try to form a new group. The first group requires 1 student, the second requires 2, and so on. The i-th group requires i students.
We loop, subtracting the required number of students for the next group from our total n, and incrementing our group count, until we no longer have enough students.
class Solution { public int maximumGroups(int[] grades) { int n = grades.length; int k = 0; int studentsNeeded = 1; while (n >= studentsNeeded) { n -= studentsNeeded; k++; studentsNeeded++; } return k; }}Complexity
Time
O(sqrt(n)). The loop runs `k` times, where `k` is the result. We know `k * (k + 1) / 2` is approximately `n`, so `k` is proportional to `sqrt(n)`.
Space
O(1), as we only use a few variables to keep track of the state.
Trade-offs
Pros
More efficient than the sorting approach as it avoids the
O(n log n)step.Simple to implement and understand.
Uses constant extra space.
Cons
Not the most optimal solution, as logarithmic or constant time solutions exist.
This approach builds upon the insight from the iterative method. We are looking for the maximum integer k that satisfies the condition 1 + 2 + ... + k <= n, which is equivalent to k * (k + 1) / 2 <= n. The function f(k) = k * (k + 1) / 2 is monotonically increasing for k > 0. This property allows us to use binary search to find the answer k efficiently.
Algorithm
- Get the total number of students,
n. - Initialize search boundaries
low = 0,high = n. - Initialize
ans = 0to store the result. - While
low <= high:- a. Calculate
mid = low + (high - low) / 2. - b. Calculate students needed for
midgroups:needed = (long)mid * (mid + 1) / 2. Uselongto prevent overflow. - c. If
needed <= n:midis a valid number of groups. Store it inansand search for a largerkby settinglow = mid + 1. - d. If
needed > n:midis too large. Search for a smallerkby settinghigh = mid - 1.
- a. Calculate
- Return
ans.
Walkthrough
We can binary search for the answer k in the range [0, n]. For a given mid value (a potential k), we can quickly check if it's possible to form mid groups.
The check involves calculating the minimum number of students required, which is mid * (mid + 1) / 2.
- If this required number is less than or equal to
n, it meansmidgroups are possible, so we try for a largerkby moving our search to the right half (low = mid + 1). We also storemidas a potential answer. - If the required number is greater than
n,midis too large, and we must try for a smallerkby moving our search to the left half (high = mid - 1).
The search continues until low crosses high, and the last valid mid we found is our answer.
class Solution { public int maximumGroups(int[] grades) { int n = grades.length; long low = 0, high = n; long ans = 0; while (low <= high) { long mid = low + (high - low) / 2; // Students needed for 'mid' groups long studentsNeeded = mid * (mid + 1) / 2; if (studentsNeeded <= n) { // 'mid' is a possible answer, try for more groups ans = mid; low = mid + 1; } else { // 'mid' is too large, try for fewer groups high = mid - 1; } } return (int)ans; }}Complexity
Time
O(log n). The binary search reduces the search space (from `0` to `n`) by half in each step.
Space
O(1), as the binary search is done in-place with a few variables.
Trade-offs
Pros
Very efficient, significantly faster than linear or
O(sqrt(n))approaches for largen.Optimal time complexity among common algorithmic approaches (excluding a direct mathematical formula).
Cons
Slightly more complex to implement than the straightforward iterative approach.
This is the most optimal approach. It directly calculates the result using a mathematical formula derived from the core inequality k * (k + 1) / 2 <= n. By solving this quadratic inequality for k, we can find the answer in constant time.
Algorithm
- Get the total number of students,
n. - Apply the formula derived from the quadratic inequality:
k = (sqrt(1 + 8n) - 1) / 2. - Since
kmust be an integer representing the number of full groups, take the floor of the result. - Return the resulting integer value of
k.
Walkthrough
The problem is to find the largest integer k satisfying k * (k + 1) / 2 <= n.
This can be rewritten as a quadratic inequality: k^2 + k - 2n <= 0.
To find the range of k that satisfies this, we first find the roots of the corresponding equation k^2 + k - 2n = 0.
Using the quadratic formula, k = (-b ± sqrt(b^2 - 4ac)) / 2a, with a=1, b=1, c=-2n, the positive root is k = (-1 + sqrt(1 + 8n)) / 2.
Since we are looking for the largest integer k that satisfies the inequality, the answer is the floor of this value. This gives us a direct formula to compute the result.
class Solution { public int maximumGroups(int[] grades) { int n = grades.length; // We need to find the largest k such that k * (k + 1) / 2 <= n. // This is equivalent to k^2 + k - 2n <= 0. // Solving k^2 + k - 2n = 0 for k gives the positive root: // k = (-1 + sqrt(1 + 8n)) / 2 // The answer is the floor of this value. double k = (Math.sqrt(1 + 8.0 * n) - 1) / 2.0; return (int) k; }}Complexity
Time
O(1). The calculation involves a few arithmetic operations and a square root, which are considered constant time operations.
Space
O(1), as it only involves a few calculations with no extra data structures.
Trade-offs
Pros
The most efficient solution possible with constant time complexity.
Elegant and concise implementation.
Cons
Requires mathematical insight to derive the formula, which might not be immediately obvious during a contest or interview.
Solutions
Solution
class Solution {public int maximumGroups(int[] grades) { int n = grades.length; int l = 0, r = n; while (l < r) { int mid = (l + r + 1) >> 1; if (1L * mid * mid + mid > n * 2L) { r = mid - 1; } else { l = mid; } } return l; }}class Solution { public: int maximumGroups ( vector < int >& grades ) { int n = grades . size (); int l = 0 , r = n ; while ( l < r ) { int mid = ( l + r + 1 ) >> 1 ; if ( 1LL * mid * mid + mid > n * 2LL ) { r = mid - 1 ; } else { l = mid ; } } return l ; } };class Solution: def maximumGroups(self, grades: List[int]) -> int: n = len(grades) return bisect_right(range(n + 1), n * 2, key=lambda x: x * x + x) - 1Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.