Alice has some number of cards and she wants to rearrange the cards into groups so that each group is of size groupSize, and consists of groupSize consecutive cards.
Given an integer array hand where hand[i] is the value written on the ith card and an integer groupSize, return true if she can rearrange the cards, or false otherwise.
Note: This problem is also known as "Divide Array in Sets of K Consecutive Numbers" (LeetCode 1296).
Input: hand = [1,2,3,6,2,3,4,7,8], groupSize = 3
Output: true
Explanation: Alice's hand can be rearranged as [1,2,3],[2,3,4],[6,7,8]
Input: hand = [1,2,3,4,5], groupSize = 4
Output: false
Explanation: Alice's hand can't be rearranged into groups of 4.
Input: hand = [1,2,3,6,2,3,4,7,8], groupSize = 1
Output: true
Explanation: Each card forms its own group.
1 <= hand.length <= 10^40 <= hand[i] <= 10^91 <= groupSize <= hand.lengthThis problem can be solved using a greedy approach combined with a frequency map and sorting:
To form groups of consecutive numbers:
hand.length % groupSize != 0, return false (can't form equal groups)The greedy choice is to always start forming a group with the smallest available card. This ensures we don't "waste" smaller cards that might be needed for other groups.
For hand = [1,2,3,6,2,3,4,7,8], groupSize = 3:
{1:1, 2:2, 3:2, 4:1, 6:1, 7:1, 8:1}{1:0, 2:1, 3:1, 4:1, 6:1, 7:1, 8:1}{1:0, 2:0, 3:0, 4:0, 6:1, 7:1, 8:1}{1:0, 2:0, 3:0, 4:0, 6:0, 7:0, 8:0}class Solution {
public boolean isNStraightHand(int[] hand, int groupSize) {
// Check if it's possible to divide into equal groups
if (hand.length % groupSize != 0) {
return false;
}
// Count frequency of each card
Map<Integer, Integer> freq = new HashMap<>();
for (int card : hand) {
freq.put(card, freq.getOrDefault(card, 0) + 1);
}
// Sort the hand
Arrays.sort(hand);
// Try to form consecutive groups
for (int card : hand) {
if (freq.get(card) > 0) {
// Try to form a group starting from this card
for (int i = 0; i < groupSize; i++) {
int needed = card + i;
if (freq.getOrDefault(needed, 0) == 0) {
return false; // Can't form consecutive group
}
freq.put(needed, freq.get(needed) - 1);
}
}
}
return true;
}
}
def isNStraightHand(hand: List[int], groupSize: int) -> bool:
# Check if it's possible to divide into equal groups
if len(hand) % groupSize != 0:
return False
# Count frequency of each card
from collections import Counter
freq = Counter(hand)
# Sort the hand
hand.sort()
# Try to form consecutive groups
for card in hand:
if freq[card] > 0:
# Try to form a group starting from this card
for i in range(groupSize):
needed = card + i
if freq[needed] == 0:
return False # Can't form consecutive group
freq[needed] -= 1
return True
You can also solve this using a min heap to always process the smallest card:
public boolean isNStraightHand(int[] hand, int groupSize) {
if (hand.length % groupSize != 0) return false;
Map<Integer, Integer> freq = new HashMap<>();
for (int card : hand) {
freq.put(card, freq.getOrDefault(card, 0) + 1);
}
PriorityQueue<Integer> minHeap = new PriorityQueue<>(freq.keySet());
while (!minHeap.isEmpty()) {
int first = minHeap.peek();
for (int i = 0; i < groupSize; i++) {
int card = first + i;
if (!freq.containsKey(card)) return false;
freq.put(card, freq.get(card) - 1);
if (freq.get(card) == 0) {
if (card != minHeap.peek()) return false;
minHeap.poll();
}
}
}
return true;
}
This approach has the same time complexity but uses a heap for cleaner logic.