Skip to content

Commit 0c3e53f

Browse files
feat: add Hand of Straights problem
- Greedy algorithm with TreeMap implementation - Multiple approaches: HashMap + Sorting, Priority Queue, Array - O(n log n) time, O(n) space complexity - Comprehensive explanations and edge cases
1 parent aca89c2 commit 0c3e53f

File tree

2 files changed

+305
-0
lines changed

2 files changed

+305
-0
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Hand of Straights
2+
3+
## Problem Statement
4+
5+
Alice has some number of cards and she wants to rearrange the cards into groups so that each group is size `groupSize`, and consists of consecutive cards.
6+
7+
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.
8+
9+
## Examples
10+
11+
**Example 1:**
12+
```
13+
Input: hand = [1,2,3,6,2,3,4,7,8], groupSize = 3
14+
Output: true
15+
Explanation: Alice's hand can be rearranged as [1,2,3],[2,3,4],[6,7,8]
16+
```
17+
18+
## Approach
19+
20+
### Method 1: Greedy Algorithm with TreeMap (Recommended)
21+
1. Use TreeMap to count card frequencies
22+
2. For each group, try to form consecutive cards
23+
3. If we can't form a group, return false
24+
4. Most efficient approach
25+
26+
**Time Complexity:** O(n log n) - TreeMap operations
27+
**Space Complexity:** O(n) - TreeMap
28+
29+
### Method 2: Greedy Algorithm with HashMap
30+
1. Use HashMap to count card frequencies
31+
2. Sort the unique cards
32+
3. For each group, try to form consecutive cards
33+
4. Less efficient than TreeMap approach
34+
35+
**Time Complexity:** O(n log n) - Sorting
36+
**Space Complexity:** O(n) - HashMap
37+
38+
## Algorithm
39+
40+
```
41+
1. Count card frequencies using TreeMap
42+
2. While TreeMap is not empty:
43+
a. Get the smallest card
44+
b. Try to form a group of consecutive cards
45+
c. If any card is missing, return false
46+
d. Decrease frequency of used cards
47+
3. Return true
48+
```
49+
50+
## Key Insights
51+
52+
- **Greedy Choice**: Always start with the smallest available card
53+
- **Local Optimum**: Form groups with consecutive cards
54+
- **Global Optimum**: Can rearrange all cards into groups
55+
- **Frequency Tracking**: Use TreeMap for efficient operations
56+
57+
## Alternative Approaches
58+
59+
1. **HashMap + Sorting**: Use HashMap and sort unique cards
60+
2. **Priority Queue**: Use priority queue for card management
61+
3. **Array**: Use array for frequency counting
62+
63+
## Edge Cases
64+
65+
- Empty hand: Return true
66+
- Single card: Return false if groupSize > 1
67+
- All same cards: Return true if count % groupSize == 0
68+
- No consecutive cards: Return false
69+
70+
## Applications
71+
72+
- Greedy algorithms
73+
- Frequency counting
74+
- Algorithm design patterns
75+
- Interview preparation
76+
- System design
77+
78+
## Optimization Opportunities
79+
80+
- **TreeMap**: Most efficient approach
81+
- **Frequency Counting**: O(n) space complexity
82+
- **Logarithmic Operations**: O(n log n) time complexity
83+
- **No Extra Space**: Use only necessary space
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
/**
2+
* Time Complexity: O(n log n) - TreeMap operations
3+
* Space Complexity: O(n) - TreeMap
4+
*/
5+
class Solution {
6+
public boolean isNStraightHand(int[] hand, int groupSize) {
7+
if (hand.length % groupSize != 0) {
8+
return false;
9+
}
10+
11+
TreeMap<Integer, Integer> cardCount = new TreeMap<>();
12+
for (int card : hand) {
13+
cardCount.put(card, cardCount.getOrDefault(card, 0) + 1);
14+
}
15+
16+
while (!cardCount.isEmpty()) {
17+
int firstCard = cardCount.firstKey();
18+
19+
for (int i = 0; i < groupSize; i++) {
20+
int card = firstCard + i;
21+
if (!cardCount.containsKey(card)) {
22+
return false;
23+
}
24+
25+
cardCount.put(card, cardCount.get(card) - 1);
26+
if (cardCount.get(card) == 0) {
27+
cardCount.remove(card);
28+
}
29+
}
30+
}
31+
32+
return true;
33+
}
34+
}
35+
36+
// Alternative approach using HashMap + Sorting
37+
class SolutionHashMap {
38+
public boolean isNStraightHand(int[] hand, int groupSize) {
39+
if (hand.length % groupSize != 0) {
40+
return false;
41+
}
42+
43+
Map<Integer, Integer> cardCount = new HashMap<>();
44+
for (int card : hand) {
45+
cardCount.put(card, cardCount.getOrDefault(card, 0) + 1);
46+
}
47+
48+
List<Integer> sortedCards = new ArrayList<>(cardCount.keySet());
49+
Collections.sort(sortedCards);
50+
51+
for (int card : sortedCards) {
52+
int count = cardCount.get(card);
53+
if (count > 0) {
54+
for (int i = 0; i < groupSize; i++) {
55+
int currentCard = card + i;
56+
if (!cardCount.containsKey(currentCard) || cardCount.get(currentCard) < count) {
57+
return false;
58+
}
59+
cardCount.put(currentCard, cardCount.get(currentCard) - count);
60+
}
61+
}
62+
}
63+
64+
return true;
65+
}
66+
}
67+
68+
// Alternative approach using Priority Queue
69+
class SolutionPriorityQueue {
70+
public boolean isNStraightHand(int[] hand, int groupSize) {
71+
if (hand.length % groupSize != 0) {
72+
return false;
73+
}
74+
75+
Map<Integer, Integer> cardCount = new HashMap<>();
76+
for (int card : hand) {
77+
cardCount.put(card, cardCount.getOrDefault(card, 0) + 1);
78+
}
79+
80+
PriorityQueue<Integer> minHeap = new PriorityQueue<>(cardCount.keySet());
81+
82+
while (!minHeap.isEmpty()) {
83+
int firstCard = minHeap.peek();
84+
85+
for (int i = 0; i < groupSize; i++) {
86+
int card = firstCard + i;
87+
if (!cardCount.containsKey(card) || cardCount.get(card) == 0) {
88+
return false;
89+
}
90+
91+
cardCount.put(card, cardCount.get(card) - 1);
92+
if (cardCount.get(card) == 0) {
93+
cardCount.remove(card);
94+
minHeap.remove(card);
95+
}
96+
}
97+
}
98+
99+
return true;
100+
}
101+
}
102+
103+
// Alternative approach using Array
104+
class SolutionArray {
105+
public boolean isNStraightHand(int[] hand, int groupSize) {
106+
if (hand.length % groupSize != 0) {
107+
return false;
108+
}
109+
110+
Map<Integer, Integer> cardCount = new HashMap<>();
111+
for (int card : hand) {
112+
cardCount.put(card, cardCount.getOrDefault(card, 0) + 1);
113+
}
114+
115+
List<Integer> sortedCards = new ArrayList<>(cardCount.keySet());
116+
Collections.sort(sortedCards);
117+
118+
for (int card : sortedCards) {
119+
int count = cardCount.get(card);
120+
if (count > 0) {
121+
for (int i = 0; i < groupSize; i++) {
122+
int currentCard = card + i;
123+
if (!cardCount.containsKey(currentCard) || cardCount.get(currentCard) < count) {
124+
return false;
125+
}
126+
cardCount.put(currentCard, cardCount.get(currentCard) - count);
127+
}
128+
}
129+
}
130+
131+
return true;
132+
}
133+
}
134+
135+
// Alternative approach using iterative
136+
class SolutionIterative {
137+
public boolean isNStraightHand(int[] hand, int groupSize) {
138+
if (hand.length % groupSize != 0) {
139+
return false;
140+
}
141+
142+
TreeMap<Integer, Integer> cardCount = new TreeMap<>();
143+
for (int card : hand) {
144+
cardCount.put(card, cardCount.getOrDefault(card, 0) + 1);
145+
}
146+
147+
while (!cardCount.isEmpty()) {
148+
int firstCard = cardCount.firstKey();
149+
150+
for (int i = 0; i < groupSize; i++) {
151+
int card = firstCard + i;
152+
if (!cardCount.containsKey(card)) {
153+
return false;
154+
}
155+
156+
cardCount.put(card, cardCount.get(card) - 1);
157+
if (cardCount.get(card) == 0) {
158+
cardCount.remove(card);
159+
}
160+
}
161+
}
162+
163+
return true;
164+
}
165+
}
166+
167+
// Alternative approach using while loop
168+
class SolutionWhileLoop {
169+
public boolean isNStraightHand(int[] hand, int groupSize) {
170+
if (hand.length % groupSize != 0) {
171+
return false;
172+
}
173+
174+
TreeMap<Integer, Integer> cardCount = new TreeMap<>();
175+
for (int card : hand) {
176+
cardCount.put(card, cardCount.getOrDefault(card, 0) + 1);
177+
}
178+
179+
while (!cardCount.isEmpty()) {
180+
int firstCard = cardCount.firstKey();
181+
182+
for (int i = 0; i < groupSize; i++) {
183+
int card = firstCard + i;
184+
if (!cardCount.containsKey(card)) {
185+
return false;
186+
}
187+
188+
cardCount.put(card, cardCount.get(card) - 1);
189+
if (cardCount.get(card) == 0) {
190+
cardCount.remove(card);
191+
}
192+
}
193+
}
194+
195+
return true;
196+
}
197+
}
198+
199+
// More concise version
200+
class SolutionConcise {
201+
public boolean isNStraightHand(int[] hand, int groupSize) {
202+
if (hand.length % groupSize != 0) return false;
203+
204+
TreeMap<Integer, Integer> cardCount = new TreeMap<>();
205+
for (int card : hand) {
206+
cardCount.put(card, cardCount.getOrDefault(card, 0) + 1);
207+
}
208+
209+
while (!cardCount.isEmpty()) {
210+
int firstCard = cardCount.firstKey();
211+
for (int i = 0; i < groupSize; i++) {
212+
int card = firstCard + i;
213+
if (!cardCount.containsKey(card)) return false;
214+
215+
cardCount.put(card, cardCount.get(card) - 1);
216+
if (cardCount.get(card) == 0) cardCount.remove(card);
217+
}
218+
}
219+
220+
return true;
221+
}
222+
}

0 commit comments

Comments
 (0)