Hand of Straights

MediumGreedyLeetCode 846 ↗World 7-14
0:00 / 0:00

Split a hand of cards into runs of consecutive values. Always start a run at the smallest card left, since nothing else can come before it.

▼

The problem

LeetCode 846 (Medium). Given a hand of cards (integers) and a group size, can the whole hand be rearranged into groups of that size where each group is a run of consecutive cards (a straight)?

Example: hand [1,2,3,6,2,3,4,7,8], group size 3 → true ([1,2,3], [2,3,4], [6,7,8]); hand [1,2,3,4,5], group size 4 → false (five cards can't split into fours).

TRY IT ON LEETCODE ▶

The solution

from collections import Counter

def is_n_straight_hand(hand, size):
    if len(hand) % size:
        return False
    count = Counter(hand)
    for start in sorted(count):
        while count[start] > 0:    # smallest left
            for card in range(start, start + size):
                if count[card] == 0:
                    return False   # a gap
                count[card] -= 1
    return True

Transcript

Hand of Straights. You're dealt a hand of cards and a group size. Can you split the whole hand into straights of that size: runs of consecutive cards, like three, four, five?

Take one, two, three, six, two, three, four, seven, eight, in groups of three. Yes: one two three, two three four, and six seven eight. But one to five in groups of four is a no: five cards can't split into fours.

The naive way tries every way to split the cards, backing up when a group fails. The choices multiply, so that's exponential.

Here's the greedy trick. Look at the smallest card left. Nothing smaller is left to come before it, so it must start a straight. Take it and the next cards up, one of each. If one is missing, the answer is false. Repeat until the hand is empty.

In code: if the hand doesn't split evenly, return false. Count the cards, and visit the values in sorted order. While a value has copies left, it starts a straight: take one of each card up to the group size. If one has run out, return false. Otherwise, return true.

Let's deal it. Count each card: a single one, two twos, two threes, and one each of four, six, seven and eight. The smallest is one: take one, two, three. Now the smallest is two: take two, three, four. The threes and fours are gone, so next is six: take six, seven, eight. Every pile is empty: true.

Sorting the values takes n log n time, and each card is taken just once. The counts take n space.

Smallest card first, build the straight, stop at a gap. That's Hand of Straights.