Hand of Straights
The drill: A hand of cards must be dealt entirely into equal-size groups, each group a run of consecutive values with no gaps and no repeats inside it. Decide whether such a full dealing is possible.
A hand of number cards needs to be split entirely into groups of a fixed size, with nothing left over. Each group must form an unbroken run of consecutive values — no gaps, and no value repeated within the same group.
Every single card in the hand has to end up in exactly one group; cards can't be discarded or held back, and a card's value can repeat across the whole hand as long as no two copies land in the same group.
The verdict needed is simply whether such a complete grouping exists for the given hand and group size — not what the groups actually look like.
- the hand size must divide evenly by the group size, or grouping fails
- card values can repeat across the hand, within reasonable numeric ranges
- every group is a run of consecutive values with no duplicate inside it
- every card in the hand must be used — none may be left ungrouped
HINT 1 THE NUDGE
The smallest remaining card has nowhere else to go — it can only ever be the START of a group, since no smaller card exists to extend below it. That fixes every group's first move.
HINT 2 THE STRUCTURE
So the strategy isn't really a choice: always start the next group at whatever card is currently smallest, and require the next groupSize−1 consecutive values to exist. Track how many of each value remain.
HINT 3 ONE STEP FROM THE ANSWER
Count every value; walk values from smallest to largest, and whenever a value still has cards left, consume groupSize copies of it and each of the next groupSize−1 values immediately. Any missing value fails the whole hand.
Hand [3,4,2,5,6,1], groupSize 3. Sorted, every value's count starts at 1 — walk smallest to largest.
class Solution:
def isNStraightHand(self, hand: List[int], groupSize: int) -> bool:
if len(hand) % groupSize != 0:
return False
count = collections.Counter(hand)
for card in sorted(count):
need = count[card]
if need <= 0:
continue
for k in range(card, card + groupSize):
if count[k] < need:
return False
count[k] -= need
return Trueclass Solution:
def isNStraightHand(self, hand: List[int], groupSize: int) -> bool:
if len(hand) % groupSize != 0:
return False
remaining = sorted(hand)
while remaining:
start = remaining[0]
temp = list(remaining)
for card in range(start, start + groupSize):
if card not in temp:
return False
temp.remove(card) # linear scan + shift, the naive part
remaining = temp
return Trueclass Solution {
public boolean isNStraightHand(int[] hand, int groupSize) {
if (hand.length % groupSize != 0) {
return false;
}
TreeMap<Integer, Integer> count = new TreeMap<>();
for (int card : hand) {
count.merge(card, 1, Integer::sum);
}
for (int card : new ArrayList<>(count.keySet())) {
int need = count.getOrDefault(card, 0);
if (need <= 0) {
continue;
}
for (int k = card; k < card + groupSize; k++) {
int have = count.getOrDefault(k, 0);
if (have < need) {
return false;
}
count.put(k, have - need);
}
}
return true;
}
}class Solution {
public boolean isNStraightHand(int[] hand, int groupSize) {
if (hand.length % groupSize != 0) {
return false;
}
List<Integer> remaining = new ArrayList<>();
for (int card : hand) {
remaining.add(card);
}
Collections.sort(remaining);
while (!remaining.isEmpty()) {
int start = remaining.get(0);
for (int card = start; card < start + groupSize; card++) {
int idx = remaining.indexOf(card); // linear scan, the naive part
if (idx == -1) {
return false;
}
remaining.remove(idx);
}
}
return true;
}
}✓ CHIP-TIMED — ALL 4 SOLUTIONS RAN GREEN AGAINST SELF-AUTHORED CASES IN CI · JDK 21 · CPYTHON 3.12 · NOTHING PUBLISHES RED