Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
There are n people that are split into some unknown number of groups. Each person is labeled with a unique ID from 0 to n - 1.
You are given an integer array groupSizes, where groupSizes[i] is the size of the group that person i is in. For example, if groupSizes[1] = 3, then person 1 must be in a group of size 3.
Return a list of groups such that each person i is in a group of size groupSizes[i].
Each person should appear in exactly one group, and every person must be in a group. If there are multiple answers, return any of them. It is guaranteed that there will be at least one valid solution for the given input.
Example 1:
Input: groupSizes = [3,3,3,3,3,1,3] Output: [[5],[0,1,2],[3,4,6]] Explanation: The first group is [5]. The size is 1, and groupSizes[5] = 1. The second group is [0,1,2]. The size is 3, and groupSizes[0] = groupSizes[1] = groupSizes[2] = 3. The third group is [3,4,6]. The size is 3, and groupSizes[3] = groupSizes[4] = groupSizes[6] = 3. Other possible solutions are [[2,1,6],[5],[0,4,3]] and [[5],[0,6,2],[4,3,1]].
Example 2:
Input: groupSizes = [2,1,3,3,3,2] Output: [[1],[0,5],[2,3,4]]
Constraints:
groupSizes.length == n1 <= n <= 5001 <= groupSizes[i] <= nProblem summary: There are n people that are split into some unknown number of groups. Each person is labeled with a unique ID from 0 to n - 1. You are given an integer array groupSizes, where groupSizes[i] is the size of the group that person i is in. For example, if groupSizes[1] = 3, then person 1 must be in a group of size 3. Return a list of groups such that each person i is in a group of size groupSizes[i]. Each person should appear in exactly one group, and every person must be in a group. If there are multiple answers, return any of them. It is guaranteed that there will be at least one valid solution for the given input.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map · Greedy
[3,3,3,3,3,1,3]
[2,1,3,3,3,2]
rabbits-in-forest)maximum-number-of-groups-with-increasing-length)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1282: Group the People Given the Group Size They Belong To
class Solution {
public List<List<Integer>> groupThePeople(int[] groupSizes) {
int n = groupSizes.length;
List<Integer>[] g = new List[n + 1];
Arrays.setAll(g, k -> new ArrayList<>());
for (int i = 0; i < n; ++i) {
g[groupSizes[i]].add(i);
}
List<List<Integer>> ans = new ArrayList<>();
for (int i = 0; i < g.length; ++i) {
List<Integer> v = g[i];
for (int j = 0; j < v.size(); j += i) {
ans.add(v.subList(j, j + i));
}
}
return ans;
}
}
// Accepted solution for LeetCode #1282: Group the People Given the Group Size They Belong To
func groupThePeople(groupSizes []int) [][]int {
n := len(groupSizes)
g := make([][]int, n+1)
for i, v := range groupSizes {
g[v] = append(g[v], i)
}
ans := [][]int{}
for i, v := range g {
for j := 0; j < len(v); j += i {
ans = append(ans, v[j:j+i])
}
}
return ans
}
# Accepted solution for LeetCode #1282: Group the People Given the Group Size They Belong To
class Solution:
def groupThePeople(self, groupSizes: List[int]) -> List[List[int]]:
g = defaultdict(list)
for i, v in enumerate(groupSizes):
g[v].append(i)
return [v[j : j + i] for i, v in g.items() for j in range(0, len(v), i)]
// Accepted solution for LeetCode #1282: Group the People Given the Group Size They Belong To
impl Solution {
pub fn group_the_people(group_sizes: Vec<i32>) -> Vec<Vec<i32>> {
let n: usize = group_sizes.len();
let mut g: Vec<Vec<usize>> = vec![Vec::new(); n + 1];
for (i, &size) in group_sizes.iter().enumerate() {
g[size as usize].push(i);
}
let mut ans: Vec<Vec<i32>> = Vec::new();
for (i, v) in g.into_iter().enumerate() {
for j in (0..v.len()).step_by(i.max(1)) {
ans.push(
v[j..(j + i).min(v.len())]
.iter()
.map(|&x| x as i32)
.collect(),
);
}
}
ans
}
}
// Accepted solution for LeetCode #1282: Group the People Given the Group Size They Belong To
function groupThePeople(groupSizes: number[]): number[][] {
const n: number = groupSizes.length;
const g: number[][] = Array.from({ length: n + 1 }, () => []);
for (let i = 0; i < groupSizes.length; i++) {
const size: number = groupSizes[i];
g[size].push(i);
}
const ans: number[][] = [];
for (let i = 1; i <= n; i++) {
const group: number[] = [];
for (let j = 0; j < g[i].length; j += i) {
group.push(...g[i].slice(j, j + i));
ans.push([...group]);
group.length = 0;
}
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Try every possible combination of choices. With n items each having two states (include/exclude), the search space is 2ⁿ. Evaluating each combination takes O(n), giving O(n × 2ⁿ). The recursion stack or subset storage uses O(n) space.
Greedy algorithms typically sort the input (O(n log n)) then make a single pass (O(n)). The sort dominates. If the input is already sorted or the greedy choice can be computed without sorting, time drops to O(n). Proving greedy correctness (exchange argument) is harder than the implementation.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.
Wrong move: Locally optimal choices may fail globally.
Usually fails on: Counterexamples appear on crafted input orderings.
Fix: Verify with exchange argument or monotonic objective before committing.