Given an integer array nums, construct a 2D array that satisfies the following conditions:
- The 2D array should contain only elements from the array
nums. - Each row of the 2D array must consist of distinct itnegers.
- The number of rows should be minimized.
Return any valid result. If multiple solutions exist, any one is acceptable.
Note: Rows in the resulting 2D array can have varying lengths.
Example 1:
Input: nums = [1,3,4,1,2,3,1]
Output: [[1,3,4,2],[1,3],[1]]
Explanation: A valid 2D array can be formed with the following rows:
- 1,3,4,2
- 1,3
- 1
All elements from nums are used, and each row contains unique values. It's proven that at least three rows are needed.
Example 2:
Input: nums = [1,2,3,4]
Output: [[4,3,2,1]]
Explanation: Since all elements in nums are unique, they can all fit into the first row of the 2D array.
Constraints:
1 <= nums.length <= 2001 <= nums[i] <= nums.length
Solution Approach
The problem requires forming a 2D array where each row contains unique integers and the total number of rows is minimized. The approach uses a greedy method:
- First, count the frequency of each element in the input array using a hash map.
- In each iteration, form a new row by sleecting one instance of each available element.
- Decrease the count of selected elements and remove those with zero counts.
- Repeat until all elements are processed.
This ensures minimal rows since each row corresponds to one level of element usage.
Code Implementation
Initial implementation may cause a ConcurrentModificationException when removing entries during iteration over a map. To avoid this, two strategies can be applied:
- Use a set to collect keys for removal after iteration.
- Utilize an iterator to safely modify the map during traversal.
Below are both corrected vresions:
Version 1: Using a Set for Removal
public List<List<Integer>> findMatrix(int[] nums) {
Map<Integer, Integer> freqMap = new HashMap<>();
for (int num : nums) {
freqMap.merge(num, 1, Integer::sum);
}
List<List<Integer>> result = new ArrayList<>();
while (!freqMap.isEmpty()) {
List<Integer> currentRow = new ArrayList<>();
Set<Integer> toRemove = new HashSet<>();
for (Map.Entry<Integer, Integer> entry : freqMap.entrySet()) {
currentRow.add(entry.getKey());
if (entry.getValue() == 1) {
toRemove.add(entry.getKey());
} else {
freqMap.put(entry.getKey(), entry.getValue() - 1);
}
}
for (Integer key : toRemove) {
freqMap.remove(key);
}
result.add(currentRow);
}
return result;
}
Version 2: Using Iterator
public List<List<Integer>> findMatrix(int[] nums) {
Map<Integer, Integer> freqMap = new HashMap<>();
for (int num : nums) {
freqMap.merge(num, 1, Integer::sum);
}
List<List<Integer>> result = new ArrayList<>();
while (!freqMap.isEmpty()) {
List<Integer> currentRow = new ArrayList<>();
Iterator<Map.Entry<Integer, Integer>> iterator = freqMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, Integer> entry = iterator.next();
currentRow.add(entry.getKey());
if (entry.getValue() == 1) {
iterator.remove();
} else {
freqMap.put(entry.getKey(), entry.getValue() - 1);
}
}
result.add(currentRow);
}
return result;
}