846. Straights hand

#include <stdbool.h>
#include <stdlib.h>

static int cmpInt(const void *a, const void *b) {
  return (*(const int *)a > *(const int *)b) - (*(const int *)a < *(const int *)b);
}

bool isNStraightHand(int *hand, int handSize, int groupSize) {
  if (handSize % groupSize != 0)
    return false;

  // C has no ordered map: sort, then collapse into distinct values + counts
  qsort(hand, handSize, sizeof(int), cmpInt);
  int *vals = malloc(handSize * sizeof(int));
  int *cnt = malloc(handSize * sizeof(int));
  int m = 0;
  for (int i = 0; i < handSize; i++) {
    if (m > 0 && vals[m - 1] == hand[i]) {
      cnt[m - 1]++;
    } else {
      vals[m] = hand[i];
      cnt[m++] = 1;
    }
  }

  bool ok = true;
  for (int i = 0; i < m && ok; i++) {
    int c = cnt[i];
    if (c == 0)
      continue; // already used up by earlier groups
    for (int j = 0; j < groupSize; j++) {
      // missing value or too few copies: group can't be built
      if (i + j >= m || vals[i + j] != vals[i] + j || cnt[i + j] < c) {
        ok = false;
        break;
      }
      cnt[i + j] -= c;
    }
  }

  free(vals);
  free(cnt);
  return ok;
}
#include <map>
#include <vector>

using namespace std;

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

    map<int, int> count;
    for (int c : hand)
      count[c]++;

    while (!count.empty()) {
      int start = count.begin()->first; // smallest remaining card

      for (int v = start; v < start + groupSize; v++) {
        auto it = count.find(v);
        if (it == count.end())
          return false; // missing value, group can't be built
        if (--it->second == 0)
          count.erase(it); // drop values that are used up
      }
    }

    return true;
  }
};
package greedy

import "sort"

func isNStraightHand(hand []int, groupSize int) bool {
    if len(hand)%groupSize != 0 {
        return false
    }

    count := make(map[int]int)
    for _, c := range hand {
        count[c]++
    }

    // ascending, so each value is the smallest remaining card when reached
    keys := make([]int, 0, len(count))
    for k := range count {
        keys = append(keys, k)
    }
    sort.Ints(keys)

    for _, start := range keys {
        c := count[start]
        if c == 0 {
            continue // already used up by earlier groups
        }
        for v := start; v < start+groupSize; v++ {
            if count[v] < c {
                return false // missing value, group can't be built
            }
            count[v] -= c
        }
    }

    return true
}
import java.util.Map;
import java.util.TreeMap;

class Solution {
    public boolean isNStraightHand(int[] hand, int groupSize) {
        if (hand.length % groupSize != 0)
            return false;

        TreeMap<Integer, Integer> count = new TreeMap<>();
        for (int c : hand)
            count.merge(c, 1, Integer::sum);

        while (!count.isEmpty()) {
            int start = count.firstKey(); // smallest remaining card

            for (int v = start; v < start + groupSize; v++) {
                Integer left = count.get(v);
                if (left == null)
                    return false; // missing value, group can't be built
                if (left == 1)
                    count.remove(v); // drop values that are used up
                else
                    count.put(v, left - 1);
            }
        }

        return true;
    }
}
/**
 * @param {number[]} hand
 * @param {number} groupSize
 * @return {boolean}
 */
var isNStraightHand = function (hand, groupSize) {
  if (hand.length % groupSize !== 0) return false;

  const count = new Map();
  for (const c of hand) count.set(c, (count.get(c) ?? 0) + 1);

  // ascending, so each value is the smallest remaining card when reached
  const keys = [...count.keys()].sort((a, b) => a - b);
  for (const start of keys) {
    const c = count.get(start);
    if (c === 0) continue; // already used up by earlier groups
    for (let v = start; v < start + groupSize; v++) {
      if ((count.get(v) ?? 0) < c) return false; // missing value, group can't be built
      count.set(v, count.get(v) - c);
    }
  }

  return true;
};
from collections import Counter
from typing import List


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

        count = Counter(hand)

        # ascending, so each value is the smallest remaining card when reached
        for start in sorted(count):
            c = count[start]
            if c == 0:
                continue  # already used up by earlier groups
            for v in range(start, start + groupSize):
                if count.get(v, 0) < c:
                    return False  # missing value, group can't be built
                count[v] -= c

        return True
use std::collections::BTreeMap;

impl Solution {
    pub fn is_n_straight_hand(hand: Vec<i32>, group_size: i32) -> bool {
        if hand.len() % group_size as usize != 0 {
            return false;
        }

        let mut count = BTreeMap::new();
        for c in hand {
            *count.entry(c).or_insert(0) += 1;
        }

        while let Some((&start, _)) = count.first_key_value() {
            // start is the smallest remaining card
            for v in start..start + group_size {
                match count.get_mut(&v) {
                    None => return false, // missing value, group can't be built
                    Some(1) => {
                        count.remove(&v); // drop values that are used up
                    }
                    Some(n) => *n -= 1,
                }
            }
        }

        true
    }
}