2784. Check if Array is Good
Problem Description
You need to determine if a given integer array nums
is "good" based on a specific definition.
An array is considered good if it's a permutation of a special array called base[n]
, where:
base[n] = [1, 2, ..., n-1, n, n]
- This means
base[n]
has lengthn + 1
- It contains each number from
1
ton-1
exactly once - The number
n
appears exactly twice
For example:
base[1] = [1, 1]
(contains one1
twice)base[3] = [1, 2, 3, 3]
(contains1
and2
once each, and3
twice)
Your task is to return true
if the given array nums
is a permutation of some base[n]
array (meaning it has the same elements with the same frequencies, just possibly in a different order), and false
otherwise.
The key requirements for a good array are:
- The length must be
n + 1
for some positive integern
- Numbers from
1
ton-1
must each appear exactly once - The number
n
must appear exactly twice - No other numbers should be present
Intuition
To check if an array is "good", we need to verify it matches the pattern of base[n]
for some value of n
.
First, let's figure out what n
should be. Since base[n]
has length n + 1
, and our input array nums
has a certain length, we can deduce that n = len(nums) - 1
.
Now we need to verify two things:
- The largest value
n
appears exactly twice - All values from
1
ton-1
appear exactly once
The most straightforward way to check these conditions is to count the occurrences of each element in nums
. We can use a frequency counter to track how many times each number appears.
Once we have the counts:
- Check if
cnt[n] == 2
(the largest element appears twice) - Check if all numbers from
1
ton-1
appear exactly once
The beauty of this approach is that we don't need to explicitly check if each count equals 1 - we can simply verify that all counts from 1
to n-1
are non-zero (truthy). If any number in this range is missing, its count would be 0 (falsy). If any number appears more than once, we'd have too many total elements for our array length, which would be caught by our check of n
appearing exactly twice.
This counting approach gives us a clean, efficient solution that directly validates the definition of a "good" array.
Learn more about Sorting patterns.
Solution Approach
The solution uses a counting approach with a hash table to verify if the array matches the required pattern.
Step 1: Count element frequencies
cnt = Counter(nums)
We use Python's Counter
from the collections module to create a frequency map of all elements in nums
. This gives us a dictionary where keys are the elements and values are their occurrence counts.
Step 2: Determine the value of n
n = len(nums) - 1
Since base[n]
has length n + 1
, and our array nums
should match this pattern, we calculate n
as len(nums) - 1
.
Step 3: Verify the conditions
return cnt[n] == 2 and all(cnt[i] for i in range(1, n))
This return statement checks two critical conditions:
-
cnt[n] == 2
: Verifies that the largest elementn
appears exactly twice in the array. -
all(cnt[i] for i in range(1, n))
: Checks that all numbers from1
ton-1
exist in the array. Theall()
function returnsTrue
only if all elements in the iterable are truthy. Sincecnt[i]
returns the count of elementi
, this will be:0
(falsy) if elementi
is missing from the array- A positive number (truthy) if element
i
exists in the array
The combination of these two checks ensures:
- The array has the correct length (
n + 1
) - Contains all required elements with correct frequencies
- No extra elements are present (since if we have all elements from
1
ton-1
once each, plusn
twice, that accounts for alln + 1
elements)
Time Complexity: O(n)
where n is the length of the input array, as we iterate through the array once to count elements and then check up to n values.
Space Complexity: O(n)
for storing the frequency counter.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with nums = [1, 2, 3, 3]
:
Step 1: Count element frequencies
cnt = Counter([1, 2, 3, 3]) # cnt = {1: 1, 2: 1, 3: 2}
We create a frequency map showing that 1
appears once, 2
appears once, and 3
appears twice.
Step 2: Determine the value of n
n = len([1, 2, 3, 3]) - 1 = 4 - 1 = 3
Since the array has length 4, we calculate n = 3
. This means we're checking if the array is a permutation of base[3] = [1, 2, 3, 3]
.
Step 3: Verify the conditions
# Check cnt[n] == 2
cnt[3] == 2 # True (3 appears twice)
# Check all(cnt[i] for i in range(1, n))
# range(1, 3) gives us [1, 2]
cnt[1] = 1 # Truthy (1 exists in array)
cnt[2] = 1 # Truthy (2 exists in array)
all([1, 1]) = True # All values are truthy
# Final result: True and True = True
The array passes both checks:
- The largest element (3) appears exactly twice β
- All elements from 1 to 2 appear at least once β
Therefore, [1, 2, 3, 3]
is a good array.
Counter-example: Let's try nums = [1, 1, 3, 3]
:
cnt = {1: 2, 3: 2}
n = 4 - 1 = 3
cnt[3] == 2 # True
all(cnt[i] for i in range(1, 3)) # range gives [1, 2]
# cnt[1] = 2 (truthy), but cnt[2] = 0 (falsy, since 2 is missing)
# all([2, 0]) = False
# Result: True and False = False
This array fails because element 2 is missing, making it not a valid permutation of base[3]
.
Solution Implementation
1from typing import List
2from collections import Counter
3
4
5class Solution:
6 def isGood(self, nums: List[int]) -> bool:
7 """
8 Determines if the given array is "good".
9
10 A "good" array of length n+1 contains:
11 - Each integer from 1 to n-1 exactly once
12 - The integer n exactly twice
13
14 Args:
15 nums: List of integers to check
16
17 Returns:
18 bool: True if the array is "good", False otherwise
19 """
20 # Count the frequency of each number in the array
21 frequency_counter = Counter(nums)
22
23 # Calculate n (the maximum expected value)
24 # Since a good array has length n+1, n = length - 1
25 n = len(nums) - 1
26
27 # Check two conditions:
28 # 1. The number n appears exactly twice
29 # 2. All numbers from 1 to n-1 appear at least once (exactly once for a valid "good" array)
30 has_n_twice = frequency_counter[n] == 2
31 has_all_numbers = all(frequency_counter[i] == 1 for i in range(1, n))
32
33 return has_n_twice and has_all_numbers
34
1class Solution {
2 public boolean isGood(int[] nums) {
3 // Calculate n based on array length (array should have n+1 elements)
4 int n = nums.length - 1;
5
6 // Create frequency array to count occurrences of each number
7 // Size 201 to handle constraint where numbers can be up to 200
8 int[] frequency = new int[201];
9
10 // Count frequency of each number in the input array
11 for (int number : nums) {
12 frequency[number]++;
13 }
14
15 // Check if the largest number n appears exactly twice
16 if (frequency[n] != 2) {
17 return false;
18 }
19
20 // Check if all numbers from 1 to n-1 appear exactly once
21 for (int i = 1; i < n; i++) {
22 if (frequency[i] != 1) {
23 return false;
24 }
25 }
26
27 // All conditions satisfied - array is "good"
28 return true;
29 }
30}
31
1class Solution {
2public:
3 bool isGood(vector<int>& nums) {
4 // Calculate n from the array size (array should have n+1 elements)
5 int n = nums.size() - 1;
6
7 // Initialize frequency array to count occurrences of each number
8 // Size 201 to handle numbers up to 200
9 int frequency[201] = {};
10
11 // Count frequency of each number in the input array
12 for (int number : nums) {
13 ++frequency[number];
14 }
15
16 // Check if the largest number n appears exactly twice
17 if (frequency[n] != 2) {
18 return false;
19 }
20
21 // Check if all numbers from 1 to n-1 appear exactly once
22 for (int i = 1; i < n; ++i) {
23 if (frequency[i] != 1) {
24 return false;
25 }
26 }
27
28 // All conditions satisfied - array is "good"
29 return true;
30 }
31};
32
1/**
2 * Checks if an array is "good" according to specific criteria:
3 * - The array should contain exactly n+1 elements where n is the largest element
4 * - Elements from 1 to n-1 should appear exactly once
5 * - Element n should appear exactly twice
6 *
7 * @param nums - The input array of numbers to check
8 * @returns true if the array is "good", false otherwise
9 */
10function isGood(nums: number[]): boolean {
11 // Calculate n as the expected maximum value (array length - 1)
12 const n: number = nums.length - 1;
13
14 // Initialize frequency counter array with 201 elements (covering range 0-200)
15 const frequencyCount: number[] = Array(201).fill(0);
16
17 // Count the frequency of each number in the input array
18 for (const num of nums) {
19 frequencyCount[num]++;
20 }
21
22 // Check if the maximum value n appears exactly twice
23 if (frequencyCount[n] !== 2) {
24 return false;
25 }
26
27 // Check if all values from 1 to n-1 appear exactly once
28 for (let i = 1; i < n; i++) {
29 if (frequencyCount[i] !== 1) {
30 return false;
31 }
32 }
33
34 // All conditions are satisfied, the array is "good"
35 return true;
36}
37
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the array nums
.
- Creating the Counter object requires iterating through all elements in
nums
, which takesO(n)
time. - Computing
n = len(nums) - 1
takesO(1)
time. - Checking
cnt[n] == 2
takesO(1)
time. - The
all()
function with the generator expressioncnt[i] for i in range(1, n)
iterates through values from 1 ton-1
, checking each value in the Counter. This takesO(n)
time in the worst case. - Overall, the dominant operation is
O(n)
, so the total time complexity isO(n)
.
The space complexity is O(n)
, where n
is the length of the array nums
.
- The Counter object stores at most
n
unique elements from the input array, requiringO(n)
space in the worst case. - The variable
n
and other temporary variables useO(1)
space. - The generator expression in
all()
doesn't create additional data structures, just iterates. - Therefore, the total space complexity is
O(n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Not Handling Edge Cases for Empty or Single Element Arrays
The current solution doesn't properly handle edge cases where the array is empty or has only one element. For an empty array, n
would be calculated as -1
, and for a single element array, n
would be 0
. Neither of these represents valid "good" arrays since:
base[0]
doesn't exist (n must be positive)- An empty array cannot be a permutation of any
base[n]
Fix:
def isGood(self, nums: List[int]) -> bool:
# Handle edge cases
if len(nums) <= 1:
return False
frequency_counter = Counter(nums)
n = len(nums) - 1
# Rest of the logic remains the same
has_n_twice = frequency_counter[n] == 2
has_all_numbers = all(frequency_counter[i] == 1 for i in range(1, n))
return has_n_twice and has_all_numbers
Pitfall 2: Incorrect Frequency Checking Logic
The original code uses all(frequency_counter[i] for i in range(1, n))
which only checks if elements exist (non-zero count) but doesn't verify they appear exactly once. This would incorrectly validate arrays where numbers from 1 to n-1 appear more than once.
Example of failure: [1, 1, 2, 3, 3]
would pass the original check even though 1
appears twice (should appear once).
Fix:
def isGood(self, nums: List[int]) -> bool:
if len(nums) <= 1:
return False
frequency_counter = Counter(nums)
n = len(nums) - 1
# Explicitly check that each number from 1 to n-1 appears exactly once
has_n_twice = frequency_counter[n] == 2
has_all_numbers_once = all(frequency_counter[i] == 1 for i in range(1, n))
# Also verify no extra numbers exist
expected_sum = sum(range(1, n)) + 2 * n # Sum of base[n]
actual_sum = sum(nums)
return has_n_twice and has_all_numbers_once and expected_sum == actual_sum
Pitfall 3: Not Validating Array Contains Only Valid Numbers
The solution doesn't check if the array contains numbers outside the valid range [1, n]. An array like [0, 1, 2, 2]
or [1, 2, 5, 5]
might pass some checks but shouldn't be considered "good".
Fix:
def isGood(self, nums: List[int]) -> bool:
if len(nums) <= 1:
return False
frequency_counter = Counter(nums)
n = len(nums) - 1
# Check that we have exactly the right set of keys
# Should have numbers 1 through n, no more, no less
if set(frequency_counter.keys()) != set(range(1, n + 1)):
return False
# Now check frequencies
has_n_twice = frequency_counter[n] == 2
has_all_numbers_once = all(frequency_counter[i] == 1 for i in range(1, n))
return has_n_twice and has_all_numbers_once
Which two pointer techniques do you use to check if a string is a palindrome?
Recommended Readings
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!