A clear explanation of checking whether card counts share a common group size using the greatest common divisor.
Problem Restatement
We are given an integer array deck.
Each value represents the number written on one card.
We need to decide whether we can split the entire deck into groups such that:
| Rule | Meaning |
|---|---|
| Same group size | Every group has exactly x cards |
| Minimum group size | x > 1 |
| Same card value | All cards in one group have the same integer |
Return True if such a partition is possible. Otherwise, return False. The official problem states the same grouping rule with x >= 2.
Input and Output
| Item | Meaning |
|---|---|
| Input | Integer array deck |
| Output | Boolean |
| Group size | Same x for every group |
| Constraint | x >= 2 |
| Group content | All cards in a group must have the same value |
Function shape:
def hasGroupsSizeX(deck: list[int]) -> bool:
...Examples
Example 1:
deck = [1, 2, 3, 4, 4, 3, 2, 1]Counts:
1 -> 2
2 -> 2
3 -> 2
4 -> 2We can choose:
x = 2Groups:
[1, 1], [2, 2], [3, 3], [4, 4]Answer:
TrueExample 2:
deck = [1, 1, 1, 2, 2, 2, 3, 3]Counts:
1 -> 3
2 -> 3
3 -> 2There is no group size greater than 1 that divides all counts.
Answer:
FalseExample 3:
deck = [1]There is only one card.
Since x must be at least 2, no valid grouping exists.
Answer:
FalseFirst Thought: Try Every Group Size
A direct method is to try every possible value of x.
The group size must be at least 2 and at most the smallest frequency.
For each x, check whether every card count is divisible by x.
from collections import Counter
class Solution:
def hasGroupsSizeX(self, deck: list[int]) -> bool:
counts = Counter(deck)
smallest = min(counts.values())
for x in range(2, smallest + 1):
valid = True
for count in counts.values():
if count % x != 0:
valid = False
break
if valid:
return True
return FalseThis works, but we can make the idea cleaner.
Key Insight
For a valid group size x, every card value count must be divisible by x.
So x must be a common divisor of all frequencies.
For example:
counts = [6, 9, 12]A valid x must divide 6, 9, and 12.
Their greatest common divisor is:
gcd(6, 9, 12) = 3Since this gcd is at least 2, we can choose x = 3.
So the problem becomes:
Find the greatest common divisor of all card frequencies. Return whether it is at least 2.
This is the standard solution.
Algorithm
- Count how many times each card value appears.
- Compute the gcd of all counts.
- If the gcd is at least
2, returnTrue. - Otherwise, return
False.
Correctness
Let the frequency of each distinct card value be:
c1, c2, c3, ..., cmIf a valid group size x exists, then each frequency must be divisible by x.
That means x is a common divisor of all frequencies.
Since x >= 2, the greatest common divisor of all frequencies must also be at least 2.
So if a valid partition exists, the algorithm returns True.
Conversely, suppose the gcd of all frequencies is g, where g >= 2.
Then every frequency is divisible by g.
For each card value, we can split its cards into groups of size g.
Each group contains only one card value, and every group has the same size g.
So a valid partition exists.
Therefore, the algorithm returns True exactly when the deck can be partitioned as required.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(n log n) | We count cards and compute gcd values |
| Space | O(n) | The frequency map may store many distinct card values |
More precisely, gcd is computed over the number of distinct values, but O(n log n) is a safe bound.
Implementation
from collections import Counter
from math import gcd
class Solution:
def hasGroupsSizeX(self, deck: list[int]) -> bool:
counts = Counter(deck)
group_gcd = 0
for count in counts.values():
group_gcd = gcd(group_gcd, count)
return group_gcd >= 2Code Explanation
Count card frequencies:
counts = Counter(deck)For example:
deck = [1, 1, 2, 2, 2, 2]gives:
1 -> 2
2 -> 4Initialize gcd as 0:
group_gcd = 0This works because:
gcd(0, x) = xThen fold all counts into one gcd value:
for count in counts.values():
group_gcd = gcd(group_gcd, count)Finally, the deck can be grouped only if the common divisor is at least 2:
return group_gcd >= 2Testing
def run_tests():
s = Solution()
assert s.hasGroupsSizeX([1, 2, 3, 4, 4, 3, 2, 1]) is True
assert s.hasGroupsSizeX([1, 1, 1, 2, 2, 2, 3, 3]) is False
assert s.hasGroupsSizeX([1]) is False
assert s.hasGroupsSizeX([1, 1]) is True
assert s.hasGroupsSizeX([1, 1, 2, 2, 2, 2]) is True
assert s.hasGroupsSizeX([0, 0, 0, 0]) is True
assert s.hasGroupsSizeX([1, 1, 1, 1, 2, 2]) is True
print("all tests passed")
run_tests()Test meaning:
| Test | Why |
|---|---|
[1, 2, 3, 4, 4, 3, 2, 1] | All counts are 2 |
[1, 1, 1, 2, 2, 2, 3, 3] | Counts have gcd 1 |
[1] | Cannot form group size at least 2 |
[1, 1] | One valid group |
[1, 1, 2, 2, 2, 2] | Counts 2 and 4 share divisor 2 |
[0, 0, 0, 0] | Card value can be 0 |
[1, 1, 1, 1, 2, 2] | Counts 4 and 2 share divisor 2 |