Hand of Straights

Medium · Greedy · Explanation and code example

Hash Map

How it works

We need to split the hand into groups of size groupSize, where each group is made of consecutive numbers and every card is used exactly once.

This approach uses only a frequency map and a simple rule:

  • Any valid group must start at the beginning of a consecutive run
  • So for a given number num, we first walk left to find the earliest possible start of its run (we keep moving left while start - 1 still exists in the hand)
  • Once we know a possible start, we try to repeatedly form consecutive groups starting from that start:
    • while there are still cards at start, we build a group: start, start+1, ..., start+groupSize-1
    • decrement counts as we use cards

By always forming groups from the earliest start in a run, we avoid skipping needed smaller cards and ensure groups remain consecutive.

Steps

  1. If len(hand) is not divisible by groupSize, return false.
  2. Build a frequency map count for all card values.
  3. For each card value num in the hand:
    • Find the earliest start of the consecutive run containing num:
      • set start = num
      • while count[start - 1] > 0, decrement start
  4. For every possible start up to num:
    • While count[start] > 0:
      • Try to create one full group starting at start
      • For each i from start to start + groupSize - 1:
        • If count[i] == 0, return false (missing a needed card)
        • Otherwise decrement count[i]
    • Move start forward by 1 and continue
  5. If all groups are formed successfully, return true.

Complexity

  • Time complexity: O(n)
  • Space complexity: O(n)

Things to watch for

Forgetting to Check Divisibility First

If the total number of cards is not divisible by groupSize, it is impossible to form complete groups. Skipping this initial check wastes time processing the array and may lead to subtle bugs where the algorithm appears to succeed but produces an invalid grouping.

Not Starting Groups from the Smallest Available Card

Groups must be formed starting from the smallest available card value to ensure consecutive sequences work correctly. Starting from an arbitrary card can leave smaller cards stranded without enough consecutive neighbors to form a valid group. Always process cards in sorted order or use a min-heap to find the smallest available value.

Failing to Decrement Counts Properly

When forming a group, each card in the consecutive sequence must have its count decremented. A common bug is forgetting to decrement or decrementing the wrong key, which causes cards to be reused or leaves cards unused. Additionally, when a card's count reaches zero, it must be handled correctly to avoid checking for cards that no longer exist.

Python code example

from typing import List
from collections import Counter

class Solution:
    def isNStraightHand(self, hand: List[int], groupSize: int) -> bool:
        if len(hand) % groupSize != 0:
            return False

        count = Counter(hand)
        for num in hand:
            start = num
            while count[start - 1]:
                start -= 1
            while start <= num:
                while count[start]:
                    for i in range(start, start + groupSize):
                        if not count[i]:
                            return False
                        count[i] -= 1
                start += 1
        return True

C++ code example

class Solution {
public:
    bool isNStraightHand(vector<int>& hand, int groupSize) {
        if (hand.size() % groupSize != 0) return false;

        unordered_map<int, int> count;
        for (int num : hand) count[num]++;

        for (int num : hand) {
            int start = num;
            while (count[start - 1] > 0) start--;
            while (start <= num) {
                while (count[start] > 0) {
                    for (int i = start; i < start + groupSize; i++) {
                        if (count[i] == 0) return false;
                        count[i]--;
                    }
                }
                start++;
            }
        }
        return true;
    }
};
Source and license

Adapted from NeetCode’s source · MIT license. Node types are supplied by LeetCode where needed.

Your recall check is in progress. Write your attempt before revealing the explanation.

Resume recall check

Browse all problem explanations