LeetCode 2784 - Check if Array is Good
The problem defines a special type of array called a "good" array. A good array must be a permutation of: This means the array must contain: - Every integer from 1 to n - 1 exactly once - The integer n exactly twice - No other numbers - Total length equal to n + 1 The input is…
Difficulty: 🟢 Easy
Topics: Array, Hash Table, Sorting
Solution
Problem Understanding
The problem defines a special type of array called a "good" array. A good array must be a permutation of:
$$base[n] = [1, 2, 3, ..., n-1, n, n]$$
This means the array must contain:
- Every integer from
1ton - 1exactly once - The integer
nexactly twice - No other numbers
- Total length equal to
n + 1
The input is an integer array nums, and we must determine whether it satisfies these conditions.
The key observation is that the largest number in the array must be n. Since n appears twice and all smaller values appear once, the expected array structure becomes fully determined once we know the maximum value.
For example:
- If the maximum value is
3, then the only valid good array is a permutation of[1, 2, 3, 3] - If the maximum value is
1, then the only valid good array is[1, 1]
The constraints are very small:
nums.length <= 100nums[i] <= 200
Because the input size is tiny, even sorting-based solutions are completely acceptable.
Several edge cases are important:
- Arrays with incorrect length relative to the maximum value
- Arrays missing some value between
1andn - 1 - Arrays where the maximum value appears more than twice or fewer than twice
- Arrays containing duplicates of smaller numbers
- The smallest possible valid input,
[1, 1]
A naive implementation can easily miss one of these conditions if it only checks frequencies partially.
Approaches
Brute Force Approach
A straightforward brute-force strategy is to generate the expected base[n] array and compare it against the given array after sorting both arrays.
The algorithm works as follows:
- Find the maximum value
ninnums - Construct the expected array:
$$[1, 2, 3, ..., n-1, n, n]$$ 3. Sort both arrays 4. Compare them element by element
This approach is correct because sorting removes ordering concerns. If both sorted arrays are identical, then nums must be a permutation of base[n].
Although this approach is already efficient enough for the constraints, it still performs sorting operations, which are not strictly necessary.
Optimal Approach
The better observation is that we only need to verify frequency conditions.
If n is the maximum element, then:
- Array length must equal
n + 1 - Values
1throughn - 1must appear exactly once - Value
nmust appear exactly twice
We can count occurrences using a hash map or frequency array and validate these conditions directly.
This avoids sorting entirely and gives linear time complexity.
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n log n) | O(n) | Sorts both arrays and compares them |
| Optimal | O(n) | O(n) | Uses frequency counting to validate required structure |
Algorithm Walkthrough
Optimal Frequency Counting Algorithm
- Find the maximum value in the array.
This maximum value represents the only possible candidate for n. Since a good array must contain numbers from 1 through n, with n repeated twice, the largest number determines the expected structure.
2. Check whether the array length equals n + 1.
A valid base[n] array always has exactly n + 1 elements because it contains:
n - 1distinct smaller numbers- Two copies of
n
If the length does not match, we can immediately return false.
3. Count the frequency of every number.
Use a hash map to store how many times each value appears.
4. Verify frequencies for values 1 through n - 1.
Every smaller number must appear exactly once. If any number is missing or appears multiple times, the array is invalid.
5. Verify the frequency of n.
The maximum value must appear exactly twice.
6. Return true if all checks pass.
Why it works
The algorithm directly validates the mathematical definition of a good array.
A good array is uniquely determined by its maximum value n. Once n is known, the required frequencies become fixed:
- Exactly one occurrence for every value from
1ton - 1 - Exactly two occurrences of
n
If every required frequency matches perfectly and the length is correct, then the array must be a permutation of base[n].
Python Solution
from typing import List
from collections import Counter
class Solution:
def isGood(self, nums: List[int]) -> bool:
n = max(nums)
if len(nums) != n + 1:
return False
frequency = Counter(nums)
for value in range(1, n):
if frequency[value] != 1:
return False
return frequency[n] == 2
The implementation begins by finding the maximum value, which represents the only possible candidate for n.
Next, the code checks whether the array length matches the required size of n + 1. This quickly eliminates impossible cases.
The Counter class from Python's collections module provides an easy way to count frequencies.
The loop validates that every integer from 1 through n - 1 appears exactly once. Finally, the algorithm checks whether n appears exactly twice.
If every condition succeeds, the function returns True.
Go Solution
func isGood(nums []int) bool {
n := 0
for _, num := range nums {
if num > n {
n = num
}
}
if len(nums) != n+1 {
return false
}
frequency := make(map[int]int)
for _, num := range nums {
frequency[num]++
}
for value := 1; value < n; value++ {
if frequency[value] != 1 {
return false
}
}
return frequency[n] == 2
}
The Go solution follows the same logic as the Python implementation.
Since Go does not provide a built-in Counter type, a map[int]int is used to track frequencies manually.
Go slices naturally handle dynamic array input, so no special handling is required for empty arrays because the constraints guarantee at least one element.
Integer overflow is not a concern because the values are very small.
Worked Examples
Example 1
Input: nums = [2, 1, 3]
Step 1: Find maximum value
| Variable | Value |
|---|---|
| n | 3 |
Step 2: Check length
Expected length:
$$n + 1 = 4$$
Actual length:
$$3$$
Since the lengths do not match, return false.
Example 2
Input: nums = [1, 3, 3, 2]
Step 1: Find maximum value
| Variable | Value |
|---|---|
| n | 3 |
Step 2: Check length
| Expected | Actual |
|---|---|
| 4 | 4 |
Valid so far.
Step 3: Count frequencies
| Number | Frequency |
|---|---|
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
Step 4: Validate numbers 1 through n - 1
| Value | Expected | Actual |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 1 | 1 |
Step 5: Validate n
| Value | Expected | Actual |
|---|---|---|
| 3 | 2 | 2 |
All conditions pass, return true.
Example 3
Input: nums = [1, 1]
Step 1: Find maximum value
| Variable | Value |
|---|---|
| n | 1 |
Step 2: Check length
| Expected | Actual |
|---|---|
| 2 | 2 |
Step 3: Count frequencies
| Number | Frequency |
|---|---|
| 1 | 2 |
There are no values from 1 to n - 1, so only the final condition matters.
1 appears exactly twice, return true.
Example 4
Input: nums = [3, 4, 4, 1, 2, 1]
Step 1: Find maximum value
| Variable | Value |
|---|---|
| n | 4 |
Step 2: Check length
| Expected | Actual |
|---|---|
| 5 | 6 |
Lengths do not match, so return false.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | One pass to find maximum, one pass to count frequencies, one pass to validate |
| Space | O(n) | Frequency map stores counts for array elements |
The algorithm performs only linear scans over the input array. Every operation inside the loops runs in constant time, giving an overall time complexity of O(n).
The frequency map may store up to n distinct values, so the auxiliary space complexity is O(n).
Test Cases
solution = Solution()
# Provided examples
assert solution.isGood([2, 1, 3]) == False # length mismatch
assert solution.isGood([1, 3, 3, 2]) == True # valid good array
assert solution.isGood([1, 1]) == True # smallest valid case
assert solution.isGood([3, 4, 4, 1, 2, 1]) == False # extra duplicate
# Boundary cases
assert solution.isGood([2, 2, 1]) == True # valid n = 2 case
assert solution.isGood([2, 1, 1]) == False # maximum appears once only
assert solution.isGood([3, 3, 3, 1, 2]) == False # maximum appears too many times
# Missing values
assert solution.isGood([1, 4, 4, 2]) == False # missing 3
assert solution.isGood([2, 2]) == False # missing 1
# Duplicate smaller values
assert solution.isGood([1, 2, 2, 3]) == False # duplicate smaller number
# Unsorted valid input
assert solution.isGood([4, 1, 3, 2, 4]) == True # permutation of base[4]
# Incorrect length
assert solution.isGood([1, 2, 3, 3, 4]) == False # invalid size
Test Case Summary
| Test | Why |
|---|---|
[2, 1, 3] |
Detects invalid length |
[1, 3, 3, 2] |
Standard valid example |
[1, 1] |
Smallest valid input |
[3, 4, 4, 1, 2, 1] |
Detects extra duplicate |
[2, 2, 1] |
Valid case for n = 2 |
[2, 1, 1] |
Maximum appears only once |
[3, 3, 3, 1, 2] |
Maximum appears too many times |
[1, 4, 4, 2] |
Missing intermediate value |
[2, 2] |
Missing required smaller value |
[1, 2, 2, 3] |
Duplicate non-maximum value |
[4, 1, 3, 2, 4] |
Valid unsorted permutation |
[1, 2, 3, 3, 4] |
Invalid array length |
Edge Cases
Smallest Possible Input
The array [1, 1] is the smallest valid good array. This case is important because there are no numbers from 1 to n - 1.
A buggy implementation might incorrectly assume that at least one smaller value must exist. The current implementation handles this correctly because the validation loop:
for value in range(1, n):
becomes an empty loop when n = 1.
Duplicate Smaller Values
An array like [1, 2, 2, 3] is invalid because the duplicate value is not the maximum.
This is a common source of mistakes if the implementation only checks whether the maximum appears twice. The frequency validation loop ensures every smaller number appears exactly once.
Missing Intermediate Values
An array such as [1, 4, 4, 2] is invalid because the number 3 is missing.
A naive implementation that only checks length and maximum frequency could incorrectly accept this array. The explicit verification of every value from 1 through n - 1 prevents this bug.
Incorrect Length
Arrays like [2, 1, 3] fail because the maximum value is 3, meaning the expected array size should be 4.
Length checking is important because even if frequencies look reasonable, the array cannot represent base[n] unless the size matches exactly. The implementation performs this validation immediately for early termination.