LeetCode 1207 - Unique Number of Occurrences
The problem gives us an integer array arr and asks whether every distinct number appears a unique number of times. In other words, we first count how many times each value occurs in the array.
Difficulty: 🟢 Easy
Topics: Array, Hash Table
Solution
LeetCode 1207 - Unique Number of Occurrences
Problem Understanding
The problem gives us an integer array arr and asks whether every distinct number appears a unique number of times.
In other words, we first count how many times each value occurs in the array. After we have all the frequencies, we must verify that no two different values share the same frequency.
For example, consider:
arr = [1,2,2,1,1,3]
The frequencies are:
1appears 3 times2appears 2 times3appears 1 time
Since the counts {3, 2, 1} are all different, the answer is true.
Now consider:
arr = [1,2]
Both 1 and 2 appear exactly once. Since two different values share the same occurrence count, the answer is false.
The input array can contain both positive and negative integers. The constraints are relatively small:
1 <= arr.length <= 1000-1000 <= arr[i] <= 1000
These limits tell us several important things:
- The array is small enough that even moderately inefficient solutions may pass.
- However, the intended solution should still use efficient counting techniques.
- Since values can repeat many times, frequency counting is the core operation.
- Negative numbers do not change the logic, because hash maps handle them naturally.
There are also several edge cases worth identifying early:
- Arrays where every value is unique, meaning every frequency is
1 - Arrays where all elements are identical
- Arrays containing negative values
- Arrays where two different numbers accidentally share the same count
- Arrays of length
1, which should always returntrue
The problem guarantees that the array is non-empty, so we never need to handle a completely empty input.
Approaches
Brute Force Approach
A brute force solution would manually count occurrences for every element by repeatedly scanning the array.
For each distinct value, we could:
- Traverse the entire array to count how many times it appears.
- Store that count.
- Compare it against the counts of all previously processed values.
This approach is correct because every value's frequency is explicitly computed and compared. However, it performs many repeated scans of the array.
If there are n elements, and we repeatedly scan the array for counts, the total work can grow to O(n²).
Although n <= 1000 is small enough that this may still pass, it is inefficient and unnecessary.
Optimal Approach
The key observation is that we only need two pieces of information:
- The frequency of each value
- Whether any frequency appears more than once
A hash map is ideal for counting frequencies because it allows constant average time insertion and lookup.
Once we build the frequency map, we can place all frequency values into a hash set. Since a set only stores unique values, we can compare:
- the number of distinct elements
- the number of distinct frequencies
If these counts are equal, then every occurrence count is unique.
This reduces the solution to linear time.
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n²) | O(n) | Repeatedly scans the array to count frequencies |
| Optimal | O(n) | O(n) | Uses a hash map for counting and a set for uniqueness checking |
Algorithm Walkthrough
- Create a hash map called
frequency_map.
This map stores how many times each integer appears in the array. The key is the integer value, and the value is its occurrence count. 2. Traverse the array once.
For each number:
- If it already exists in the map, increment its count.
- Otherwise, initialize its count to
1.
After this step, the map contains the frequency of every distinct value. 3. Extract all frequency counts.
The values of the hash map represent the occurrence counts we care about. 4. Insert the frequencies into a hash set.
A set automatically removes duplicates. If two numbers have the same occurrence count, the set size becomes smaller than the number of map entries. 5. Compare sizes.
- If the number of frequencies in the set equals the number of keys in the map, all frequencies are unique.
- Otherwise, at least two values share the same frequency.
- Return the result.
Why it works
The algorithm works because every distinct number contributes exactly one frequency count. A set only keeps unique values, so if two numbers share the same occurrence count, the duplicate frequency is collapsed into one set entry. Therefore:
- Equal sizes mean all frequencies are unique.
- Different sizes mean at least one frequency is duplicated.
This directly matches the problem requirement.
Python Solution
from typing import List
class Solution:
def uniqueOccurrences(self, arr: List[int]) -> bool:
frequency_map = {}
for number in arr:
frequency_map[number] = frequency_map.get(number, 0) + 1
frequencies = set(frequency_map.values())
return len(frequencies) == len(frequency_map)
The implementation begins by creating a dictionary called frequency_map. This dictionary stores how many times each number appears in the array.
The loop iterates through every element in arr. For each number, the count is updated using:
frequency_map.get(number, 0) + 1
This retrieves the current count if the number already exists, or uses 0 as the default value if it does not.
After counting is complete, the dictionary values are converted into a set:
frequencies = set(frequency_map.values())
Because sets only contain unique elements, duplicate occurrence counts are automatically removed.
Finally, the code compares:
len(frequencies) == len(frequency_map)
If these sizes match, every frequency was unique.
Go Solution
func uniqueOccurrences(arr []int) bool {
frequencyMap := make(map[int]int)
for _, number := range arr {
frequencyMap[number]++
}
frequencySet := make(map[int]bool)
for _, frequency := range frequencyMap {
if frequencySet[frequency] {
return false
}
frequencySet[frequency] = true
}
return true
}
The Go implementation follows the same logic as the Python version.
A map[int]int is used to count frequencies. Go automatically initializes missing integer map values to 0, so incrementing with:
frequencyMap[number]++
works naturally.
Instead of using a dedicated set type, Go simulates a set with:
map[int]bool
If a frequency already exists in the set map, the function immediately returns false.
Go does not require special handling for empty versus nil slices here because the problem guarantees at least one element. Integer overflow is also not a concern because the maximum frequency is only 1000.
Worked Examples
Example 1
arr = [1,2,2,1,1,3]
Step 1: Build Frequency Map
| Current Number | Frequency Map |
|---|---|
| 1 | {1: 1} |
| 2 | {1: 1, 2: 1} |
| 2 | {1: 1, 2: 2} |
| 1 | {1: 2, 2: 2} |
| 1 | {1: 3, 2: 2} |
| 3 | {1: 3, 2: 2, 3: 1} |
Step 2: Extract Frequencies
[3, 2, 1]
Step 3: Insert Into Set
{1, 2, 3}
Step 4: Compare Sizes
| Structure | Size |
|---|---|
| Frequency Map | 3 |
| Frequency Set | 3 |
Since the sizes match, return:
true
Example 2
arr = [1,2]
Step 1: Build Frequency Map
| Current Number | Frequency Map |
|---|---|
| 1 | {1: 1} |
| 2 | {1: 1, 2: 1} |
Step 2: Extract Frequencies
[1, 1]
Step 3: Insert Into Set
{1}
Step 4: Compare Sizes
| Structure | Size |
|---|---|
| Frequency Map | 2 |
| Frequency Set | 1 |
The sizes differ, so return:
false
Example 3
arr = [-3,0,1,-3,1,1,1,-3,10,0]
Step 1: Build Frequency Map
| Number | Count |
|---|---|
| -3 | 3 |
| 0 | 2 |
| 1 | 4 |
| 10 | 1 |
Step 2: Frequencies
[3, 2, 4, 1]
Step 3: Convert to Set
{1, 2, 3, 4}
Step 4: Compare Sizes
| Structure | Size |
|---|---|
| Frequency Map | 4 |
| Frequency Set | 4 |
Return:
true
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | One pass to count frequencies and another pass over distinct values |
| Space | O(n) | Hash map and set may each store up to n distinct elements |
The algorithm processes each element in the array exactly once while building the frequency map. The second phase iterates through the distinct values, which is at most n.
The extra memory comes from storing frequencies and unique counts in hash-based data structures.
Test Cases
solution = Solution()
assert solution.uniqueOccurrences([1, 2, 2, 1, 1, 3]) is True
# Standard example with unique frequencies
assert solution.uniqueOccurrences([1, 2]) is False
# Both numbers appear once
assert solution.uniqueOccurrences([-3, 0, 1, -3, 1, 1, 1, -3, 10, 0]) is True
# Includes negative numbers and multiple frequencies
assert solution.uniqueOccurrences([5]) is True
# Single element array
assert solution.uniqueOccurrences([7, 7, 7, 7]) is True
# Only one distinct number
assert solution.uniqueOccurrences([1, 1, 2, 2]) is False
# Two numbers share the same frequency
assert solution.uniqueOccurrences([1, 1, 1, 2, 2, 3]) is True
# Frequencies are 3, 2, and 1
assert solution.uniqueOccurrences([1, 1, 2, 2, 3, 3]) is False
# All frequencies are duplicated
assert solution.uniqueOccurrences([0, 0, 0, -1, -1, 2]) is True
# Mix of zero, negative, and positive values
assert solution.uniqueOccurrences(list(range(1000))) is False
# Every number appears once
Test Case Summary
| Test | Why |
|---|---|
[1,2,2,1,1,3] |
Standard valid example |
[1,2] |
Detects duplicate frequency counts |
[-3,0,1,-3,1,1,1,-3,10,0] |
Verifies negative numbers work correctly |
[5] |
Smallest valid input size |
[7,7,7,7] |
Single distinct value |
[1,1,2,2] |
Two values share frequency 2 |
[1,1,1,2,2,3] |
Frequencies are all unique |
[1,1,2,2,3,3] |
Multiple duplicated frequencies |
[0,0,0,-1,-1,2] |
Mixed integer values |
list(range(1000)) |
Large input where all frequencies are 1 |
Edge Cases
One important edge case is an array containing only one element. In this situation, there is only one frequency, which is automatically unique. A careless implementation might overcomplicate the logic or incorrectly assume at least two distinct values exist. The current solution handles this naturally because both the map and set contain exactly one entry.
Another important case is when every number appears exactly once. For example:
[1,2,3,4]
All frequencies become 1, meaning the set only contains one value while the map contains four keys. Some incorrect implementations only check adjacent values or forget to verify duplicates globally. Using a set guarantees all duplicate frequencies are detected.
A third edge case involves negative numbers and zero. Since array values range from -1000 to 1000, the implementation must correctly count negative integers as hash map keys. Both Python dictionaries and Go maps fully support negative integer keys, so no additional logic is required.
A final subtle case occurs when many different numbers share the same frequency. For example:
[1,1,2,2,3,3]
Every value appears twice. A naive implementation might stop checking too early or fail to compare all counts. The set-based approach immediately reveals the issue because all three frequencies collapse into a single set value.