2206. Divide Array Into Equal Pairs
Problem Description
You have an integer array nums
that contains exactly 2 * n
integers.
Your task is to determine if you can divide all elements in nums
into n
pairs where:
- Every element in the array must be assigned to exactly one pair (no element can be left unpaired or used in multiple pairs)
- Both elements in each pair must have the same value (equal elements)
Return true
if such a division is possible, otherwise return false
.
For example, if nums = [3,2,3,2,2,2]
, you can form 3 pairs: (3,3)
, (2,2)
, and (2,2)
, so the answer would be true
.
The key insight is that for pairing to be possible, each unique value in the array must appear an even number of times. If any value appears an odd number of times, it's impossible to pair all its occurrences, making the division impossible.
Intuition
Think about what it means to form pairs with equal elements. If we have a value that appears in the array, we need to pair each occurrence of that value with another occurrence of the same value.
Consider a simple example: if the number 5
appears 3 times in the array, can we pair all three occurrences? We can pair two of them together to form one pair (5,5)
, but we'll have one 5
left over with no partner. This tells us that any value appearing an odd number of times makes pairing impossible.
On the other hand, if a value appears an even number of times (like 2, 4, 6, etc.), we can always pair them up completely. For instance, if 7
appears 4 times, we can form 2 pairs: (7,7)
and (7,7)
.
This observation leads to a simple rule: for the array to be divisible into n
pairs of equal elements, every unique value must appear an even number of times. If even one value appears an odd number of times, we cannot form the required pairs.
Therefore, the solution becomes straightforward - count the frequency of each element in the array and check if all frequencies are even. We can use a Counter or hash table to track frequencies, then verify that each count is divisible by 2 (i.e., count % 2 == 0
).
Solution Approach
The implementation uses a counting approach with a hash table to track element frequencies.
Step 1: Count Element Frequencies
We use Python's Counter
from the collections module to create a frequency map of all elements in the array. The Counter(nums)
creates a dictionary-like object where:
- Keys are the unique elements from
nums
- Values are the count of how many times each element appears
For example, if nums = [1,2,3,3,2,1]
, then cnt = Counter(nums)
would give us {1: 2, 2: 2, 3: 2}
.
Step 2: Check All Frequencies are Even
We iterate through all the frequency values using cnt.values()
and check if each frequency is even using the modulo operator v % 2 == 0
. This expression returns True
if the value is even (divisible by 2) and False
if it's odd.
The all()
function returns True
only if all elements in the iterable are True
. So all(v % 2 == 0 for v in cnt.values())
will:
- Return
True
if every unique element appears an even number of times - Return
False
if at least one element appears an odd number of times
Time Complexity: O(n)
where n
is the length of the array, as we traverse the array once to count frequencies and then check each unique value once.
Space Complexity: O(k)
where k
is the number of unique elements in the array, needed to store the frequency map.
This solution elegantly determines if pairing is possible by verifying the necessary and sufficient condition: all elements must have even frequencies.
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,3,2,1,3,2,2,2]
.
Step 1: Count Element Frequencies
First, we create a frequency map using Counter
:
- Element
1
appears 2 times - Element
2
appears 4 times - Element
3
appears 2 times
So our frequency map is: {1: 2, 2: 4, 3: 2}
Step 2: Check if All Frequencies are Even
Now we check each frequency value:
- Frequency of
1
is 2 →2 % 2 = 0
✓ (even) - Frequency of
2
is 4 →4 % 2 = 0
✓ (even) - Frequency of
3
is 2 →2 % 2 = 0
✓ (even)
Since all frequencies are even, we return true
.
We can verify this is correct by forming the pairs:
- Two
1
s form pair(1,1)
- Four
2
s form pairs(2,2)
and(2,2)
- Two
3
s form pair(3,3)
This gives us 4 pairs from 8 elements, satisfying the requirement.
Counter-example: If we had nums = [1,2,3,4]
, the frequency map would be {1: 1, 2: 1, 3: 1, 4: 1}
. Since all frequencies are odd (1), we'd return false
- it's impossible to pair elements when each appears only once.
Solution Implementation
1from typing import List
2from collections import Counter
3
4class Solution:
5 def divideArray(self, nums: List[int]) -> bool:
6 """
7 Determines if an array can be divided into pairs where each pair contains equal elements.
8
9 Args:
10 nums: List of integers to be divided into pairs
11
12 Returns:
13 True if the array can be divided into pairs of equal elements, False otherwise
14 """
15 # Count the frequency of each number in the array
16 frequency_count = Counter(nums)
17
18 # Check if all numbers appear an even number of times
19 # For the array to be divisible into pairs, each unique number must appear an even count
20 return all(count % 2 == 0 for count in frequency_count.values())
21
1class Solution {
2 public boolean divideArray(int[] nums) {
3 // Create a frequency array to count occurrences of each number
4 // Size 510 assumes the constraint that numbers are in range [1, 500]
5 int[] frequencyCount = new int[510];
6
7 // Count the frequency of each number in the input array
8 for (int number : nums) {
9 frequencyCount[number]++;
10 }
11
12 // Check if all numbers appear an even number of times
13 // For the array to be divided into pairs, each unique number must appear an even count
14 for (int count : frequencyCount) {
15 if (count % 2 != 0) {
16 // If any number appears an odd number of times, pairing is impossible
17 return false;
18 }
19 }
20
21 // All numbers appear an even number of times, so pairing is possible
22 return true;
23 }
24}
25
1class Solution {
2public:
3 bool divideArray(vector<int>& nums) {
4 // Array to store frequency count of each number (1 to 500)
5 // Initialize all elements to 0
6 int frequency[510]{};
7
8 // Count the frequency of each number in the input array
9 for (int num : nums) {
10 ++frequency[num];
11 }
12
13 // Check if all numbers appear an even number of times
14 // If any number appears an odd number of times, we cannot divide into pairs
15 for (int i = 1; i <= 500; ++i) {
16 if (frequency[i] % 2 != 0) {
17 return false;
18 }
19 }
20
21 // All numbers appear an even number of times, can be divided into pairs
22 return true;
23 }
24};
25
1/**
2 * Determines if an array can be divided into pairs of equal elements
3 * @param nums - The input array of integers
4 * @returns true if the array can be divided into pairs, false otherwise
5 */
6function divideArray(nums: number[]): boolean {
7 // Create a frequency counter array for numbers in range [0, 500]
8 // Index represents the number, value represents its frequency
9 const frequencyCounter: number[] = Array(501).fill(0);
10
11 // Count the frequency of each number in the input array
12 for (const num of nums) {
13 frequencyCounter[num]++;
14 }
15
16 // Check if all numbers appear an even number of times
17 // If any number appears odd times, it cannot form pairs
18 for (const frequency of frequencyCounter) {
19 // Use bitwise AND to check if frequency is odd (odd & 1 = 1, even & 1 = 0)
20 if (frequency & 1) {
21 return false;
22 }
23 }
24
25 // All numbers have even frequencies, can be divided into pairs
26 return true;
27}
28
Time and Space Complexity
Time Complexity: O(n)
The algorithm iterates through the input array nums
once to build the frequency counter using Counter(nums)
, which takes O(n)
time where n
is the length of the array. Then, it iterates through all values in the counter dictionary to check if each frequency is even. In the worst case, every element is unique, resulting in n
values to check, but this is still O(n)
. The modulo operation for each value takes O(1)
time. Therefore, the overall time complexity is O(n) + O(n) = O(n)
.
Space Complexity: O(n)
The Counter
object stores the frequency of each unique element in the array. In the worst case, when all elements are unique, the counter will store n
key-value pairs, requiring O(n)
space. Even in the best case where all elements are the same, it would only store one key-value pair (O(1)
), but we consider the worst-case scenario for space complexity analysis. Therefore, the space complexity is O(n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting Edge Cases with Empty or Odd-Length Arrays
A common mistake is not considering that the input array must have an even length for pairing to be possible. While the problem states the array contains exactly 2 * n
integers, defensive programming suggests validating this assumption.
Pitfall Example:
def divideArray(self, nums: List[int]) -> bool:
# Directly counting without checking array length
frequency_count = Counter(nums)
return all(count % 2 == 0 for count in frequency_count.values())
Solution:
def divideArray(self, nums: List[int]) -> bool:
# First check if array length is even
if len(nums) % 2 != 0:
return False
frequency_count = Counter(nums)
return all(count % 2 == 0 for count in frequency_count.values())
2. Manual Frequency Counting with Incorrect Logic
When implementing without Counter
, developers often make mistakes in the counting logic or checking phase.
Pitfall Example:
def divideArray(self, nums: List[int]) -> bool:
freq = {}
for num in nums:
freq[num] = 1 # Wrong: This resets count to 1 each time
for count in freq.values():
if count % 2 != 0:
return False
return True
Solution:
def divideArray(self, nums: List[int]) -> bool:
freq = {}
for num in nums:
freq[num] = freq.get(num, 0) + 1 # Correct: Increment the count
for count in freq.values():
if count % 2 != 0:
return False
return True
3. Misunderstanding the Pairing Requirement
Some might think they need to actually create the pairs or track which elements are paired together, leading to unnecessary complexity.
Pitfall Example:
def divideArray(self, nums: List[int]) -> bool:
nums.sort()
pairs = []
i = 0
while i < len(nums) - 1:
if nums[i] == nums[i + 1]:
pairs.append((nums[i], nums[i + 1]))
i += 2
else:
return False
return len(pairs) == len(nums) // 2
Solution: The frequency-based approach is simpler and more efficient. We only need to verify that pairing is possible, not actually construct the pairs:
def divideArray(self, nums: List[int]) -> bool:
frequency_count = Counter(nums)
return all(count % 2 == 0 for count in frequency_count.values())
4. Using Sets Instead of Frequency Counting
Attempting to use sets to check for duplicates without considering the actual count of each element.
Pitfall Example:
def divideArray(self, nums: List[int]) -> bool:
unique_nums = set(nums)
return len(nums) == 2 * len(unique_nums) # Wrong logic
This incorrectly assumes each unique number appears exactly twice, which isn't always the case.
Solution: Always use frequency counting to track the exact number of occurrences for each element, as the same number might need to form multiple pairs.
How many ways can you arrange the three letters A, B and C?
Recommended Readings
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
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!