---
# System prepended metadata

title: 846. Hand of Straights
tags: [Greedy, Medium]

---

## Question

###### tags: `Greedy` `Medium`

>[846. Hand of Straights](https://leetcode.com/problems/hand-of-straights/description/)

<br>

:::info
:::spoiler *Optimal Space & Time Complexity*
<br>

```
- Time complexity: O()
- Space complexity: O()
```
:::

<br>

## Thoughts & Solutions


### YC
:::spoiler Code
```javascript=
/**
 * @param {number[]} hand
 * @param {number} groupSize
 * @return {boolean}
 */

// Time: O(n^2), Space: O(n)

var isNStraightHand = function(hand, groupSize) {
    if (hand.length % groupSize !== 0) return false;
    hand.sort((a, b) => a - b);
    let count = 0;
    let consecutiveVal = 0;
    let pointer = 0;
    while(count < hand.length){ // O(n)
        if(count % groupSize === 0){
            if(hand[pointer] !== -1){
                consecutiveVal = hand[pointer];
                hand[pointer] = -1;
                count++;
            }else{
                pointer++;
            }
        }else{
            const index = hand.indexOf(consecutiveVal + 1) // O(n)
            if(index === -1) return false
            
            consecutiveVal = hand[index];
            hand[index] = -1;
            count++;
        }
    }
    return true;
};
```
:::

<hr/>

### Sol
:::spoiler Code
```javascript=
var isNStraightHand = function(hand, groupSize) {
    if(hand.length % groupSize > 0) return false;
    hand.sort((a,b)=>a-b)
    const countMap = {}
    for(let i =0; i< hand.length; i++){
        countMap[hand[i]] = (countMap[hand[i]] || 0) +1
    }
    for(let i =0; i< hand.length-1; i++){
        if( countMap[hand[i]] > 0){ // 2
            // Try to form a group starting from this card, 2, 3, 4
            for(let j= hand[i]; j< hand[i] + groupSize;j++){
                if(countMap[j] > 0){
                    countMap[j] = countMap[j] - 1
                }else{
                    return false;
                }
            }
        }
    }
    return true;
};

```
:::

<hr/>

### 東
![Screenshot 2024-07-15 at 20.50.28](https://hackmd.io/_uploads/BkWzsqGOC.png)

:::spoiler Code
```javascript=
// Time O(m*n) | Space O(m) - m is length of hand, n is groupSize
var isNStraightHand = function(hand, groupSize) {
    hand.sort((a, b) => a - b);
    const cardMap = new Map();
    for(const card of hand) {
        if(cardMap.has(card)) {
            cardMap.set(card, cardMap.get(card) + 1);
        } else {
            cardMap.set(card, 1);
        }
    }

    const mapIter = cardMap.keys();
    let startCard = null;
    while(true) {
        startCard = mapIter.next().value;
        if(startCard === undefined) break;
        
        const startCardCount = cardMap.get(startCard);
        if(startCardCount === 0) continue;
        for(let i = 0; i < groupSize; i++) {
            if(!cardMap.has(startCard + i) || cardMap.get(startCard + i) < startCardCount) return false;
            cardMap.set(startCard + i, cardMap.get(startCard + i) - startCardCount);
        } 
    }

    return true;
};

```
:::

<hr/>

### Jessie

Time Complexity: O(n log n) due to sorting, where n is the number of cards.
Space Complexity: O(n) due to the countMap, where n is the number of cards.
:::spoiler Code
```javascript=
/**
 * @param {number[]} cards
 * @param {number} groupSize
 * @return {boolean}
 */
var isNStraightHand = function (cards, groupSize) {
  if (cards.length % groupSize !== 0) return false;

  cards.sort((a, b) => a - b);

  const countMap = new Map();

  //  計算每張牌的數量
  for (let card of cards) {
    countMap.set(card, (countMap.get(card) || 0) + 1);
  }

  let countRemoved = 0;
  for (let card of cards) {
    if (countRemoved === cards.length) break; //  所有牌都拿完的時候可以不用繼續跑完剩下的
    if (countMap.get(card) === 0) continue;

    //  以目前 card 為起始點按照 groupSize 檢查是否是連續的卡
    for (let i = 0; i < groupSize; i++) {
      let currentCard = card + i;

      //  沒有連續的卡, 或是連續的卡沒了
      if ([undefined, 0].includes(countMap.get(currentCard))) return false;

      //  檢查一個就拿掉一張
      countMap.set(currentCard, countMap.get(currentCard) - 1);
      countRemoved++;
    }
  }

  return true;
};
```
:::

<hr/>

### Howard

:::spoiler Code
```python=
class Solution:
    def isNStraightHand(self, hand: List[int], groupSize: int) -> bool:
        # idea: use counter and heap
        # time O(nlogn)
        # space O(n)

        # check divisible
        if len(hand) % groupSize:
            return False

        # build counter and heap
        counter = defaultdict(int)
        heap = []
        for h in hand:
            counter[h] += 1
            if counter[h] == 1:
                heapq.heappush(heap, h)

        # go through counter from start
        group_count = 0
        while group_count < len(hand) // groupSize:
            gi = 0
            current_card = heap[0]  # smallest card left
            while gi < groupSize:
                # if cannot form group consecutively, return False
                if current_card not in counter:
                    return False
                counter[current_card] -= 1
                if counter[current_card] == 0:
                    heapq.heappop(heap)
                    counter.pop(current_card)
                current_card += 1
                gi += 1
            group_count += 1
        
        return True
```
:::

<hr/>

### Haoyu

:::spoiler Code
```javascript=
/**
 * @param {number[]} hand
 * @param {number} groupSize
 * @return {boolean}
 */
var isNStraightHand = function(hand, groupSize) {
    const sorted = [...hand].sort((a, b) => a - b);
    const unsatisfiedGroupRecord = {};

    let toGroup = sorted.shift();

    while (toGroup !== undefined) {
        const targetGroup = unsatisfiedGroupRecord[toGroup]?.[0];

        const pushUnsatisfiedGroup = (index, group) => {
            if (!unsatisfiedGroupRecord[index]) (unsatisfiedGroupRecord[index] = []);
            unsatisfiedGroupRecord[index].push(group);
        };

        if (targetGroup) {
            targetGroup.push(toGroup);
            unsatisfiedGroupRecord[toGroup].shift();

            if (targetGroup.length < groupSize) pushUnsatisfiedGroup(toGroup + 1, targetGroup)
        } else {
            const newGroup = [toGroup];

            if (newGroup.length < groupSize) pushUnsatisfiedGroup(toGroup + 1, newGroup)
        };

        toGroup = sorted.shift();
    }

    return !Object.values(unsatisfiedGroupRecord).reduce((acc, value) => acc + value.length, 0);
};

```
:::

<hr/>

<br>

## Live Coding

:::spoiler (name)
```
// write your code here
```
:::


