Problem
Alice has some number of cards and she wants to rearrange the cards into groups so that each group is of size groupSize, and consists of groupSize consecutive cards.
Given an integer array hand where hand[i] is the value written on the ith card and an integer groupSize, return true if she can rearrange the cards, or false otherwise.
This question is the same as Leetcode 1296: https://leetcode.com/problems/divide-array-in-sets-of-k-consecutive-numbers/, which states:
Given an array of integers nums and a positive integer k, check whether it is possible to divide this array into sets of k consecutive numbers.
Return true if it is possible. Otherwise, return false.
Examples
Example 1:
| |
Example 2:
| |
Solution
groupSize is like a fixed-size window W, and we have to find the card in sequence based in all the windows.
Also, second thing is hand size n should be multiple of W. Like in eg. 1, W is 3, and n = 9, so we were able to form 3 groups.
Here is the video explanation:
Method 1 - Using Frequency Hashmap and Greedily Try to Form Groups
- Count number of different cards to a map
count - Loop from the smallest card number.
- Everytime we meet a new card
i, we cut offi-i + W - 1from the counter.
Here we can use treemap, as we need to pick smallest card.
Code
| |
| |
Dry Run
First, the hand array is sorted using a TreeMap which also counts the number of occurrences of each card. Here’s the initial cardCounts after sorting and counting:
| |
The algorithm will iterate through the cardCounts keys to try and form groups of groupSize = 3.
- Start with the smallest card
1:cardCounts[1]is1. We need cards2and3to complete the group.cardCounts[2]decreases by1(from2to1)cardCounts[3]decreases by1(from2to1) The group[1,2,3]is formed and we continue.
| |
- Next card is
2:cardCounts[2]is1. Again, we need cards3and4to complete the group.cardCounts[3]decreases by1(from1to0)cardCounts[4]decreases by1(from1to0) The group[2,3,4]is formed and we continue.
| |
The algorithm skips the card
3becausecardCounts[3]is now0, which means there’s no more3to be used for grouping.The next card with a non-zero count is
6:cardCounts[6]is1. We try to form a group with cards6,7, and8.cardCounts[7]decreases by1(from1to0)cardCounts[8]decreases by1(from1to0) The group[6,7,8]is formed and we complete the grouping successfully.
| |
The remaining cardCounts are all 0, indicating there are no more cards left and that we’ve successfully grouped all cards without breaking the group-size constraints of 3.
Since we didn’t encounter a situation where we couldn’t form a valid group, the function would return true, indicating that the grouping is indeed possible with the given hand and groupSize.
Complexity
- ⏰ Time complexity:
O(n log n + nw)wherenis the number of different cards. - 🧺 Space complexity:
O(n)for storing values in treemap.
Method 2 - Using MinHeap but inefficient
In above solution, as groupSize OR W is small, we can loop and look into the hashmap again and again. But what if we are not lucky? groupSize is very large. Then priority queue may help.
However, if we use heap.remove() the complexity becomes O(n^2).
Code
| |
Method 3 - Using MinHeap but efficient
Code
| |
Dry run
Let’s perform a dry run of the isNStraightHand method with an example hand array and a groupSize. We’ll use the hand array [1,2,3,6,2,3,4,7,8] and groupSize of 3 to walk through the method step-by-step.
First, the hand array is sorted and counts of each card are stored in a TreeMap to ensure the keys (card numbers) are in natural order. Here’s the cardCounts after the loop:
| |
A PriorityQueue (minHeap) is initialized with the keys from cardCounts to facilitate ordered access to the smallest card numbers (it serves the same purpose as the iteration over keys in a TreeMap):
| |
Now, we begin the process of forming groups:
- Poll
1from theminHeap:- Card count for
1is1. This is the start of a new group. - Need to check for cards
2(count should be at least1) and3(count should be at least1).
- Card count for
The cardCounts after forming group [1,2,3]:
| |
- Poll
2from theminHeap(since1’s count is now0):- Card count for
2is1. Form a group with2. - Check for cards
3(count should be at least1) and4(count should be at least1).
- Card count for
The cardCounts after forming group [1,2,3] and [2,3,4]:
| |
Poll
3from theminHeap; however, its count is0, so continue without doing anything.Poll
4from theminHeap; its count is0, so continue.Poll
6from theminHeap:- Card count for
6is1. This starts a new group. - For a valid group, we need cards
7(count should be at least1) and8(count should be at least1).
- Card count for
Now the cardCounts after forming group [1,2,3], [2,3,4], and [6,7,8]:
| |
- All remaining cards in the
minHeaphave a count of0, and the method finishes withtrue.
During the whole process, we didn’t encounter any situation where we were unable to form a group of size groupSize starting with the polled card number. Therefore, the method correctly returns true, indicating it is possible to partition the hand into consecutive groups of the given size.
Complexity
- ⏰ Time complexity:
O(n * log n)- n is number of distinct numbers in hand, but in worst case all the elements - 🧺 Space complexity:
O(n)