LC 846. 一手顺子
题目描述
这是 LeetCode 上的 846. 一手顺子 ,难度为 中等。
Alice
手中有一把牌,她想要重新排列这些牌,分成若干组,使每一组的牌数都是 groupSize
,并且由 groupSize
张连续的牌组成。
给你一个整数数组 hand
其中 hand[i]
是写在第 i
张牌,和一个整数 groupSize
。
如果她可能重新排列这些牌,返回 true
,否则,返回 false
。
示例 1:1
2
3
4
5输入:hand = [1,2,3,6,2,3,4,7,8], groupSize = 3
输出:true
解释:Alice 手中的牌可以被重新排列为 [1,2,3],[2,3,4],[6,7,8]。
示例 2:1
2
3
4
5输入:hand = [1,2,3,4,5], groupSize = 4
输出:false
解释:Alice 手中的牌无法被重新排列成几个大小为 4 的组。
提示:
- $1 <= hand.length <= 10^4$
- $0 <= hand[i] <= 10^9$
- $1 <= groupSize <= hand.length$
模拟 + 哈希表 + 优先队列(堆)
为了方便,我们令 $m = groupSize$。
题目要求我们将 hand
分为若干份大小为 $m$ 的顺子。
在给定 hand
的情况下,划分方式唯一确定,因此本质上这是一个「模拟」的过程。
具体的,我们可以使用「哈希表」对 hand
中的数值进行「出现次数」统计,并用于后续 实时 维护剩余元素的出现次数。
然后使用优先队列维护(小根堆)所有的 hand[i]
。每次从优先队列(堆)中取出堆顶元素 $t$ 来 尝试作为「顺子」的发起点/首个元素(当然 $t$ 能够作为发起点的前提是 $t$ 仍是剩余元素,即实时维护的出现次数不为 $0$ ),然后用 $t$ 作为发起点/首个元素构造顺子,即对 $[t, t + 1, … , t + m - 1]$ 元素的出现次数进行 $-1$ 操作。
若构造过程中没有出现「剩余元素出现次数」不足以 $-1$ 的话,说明整个构造过程没有冲突,返回 True
,否则返回 False
。
Java 代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class Solution {
public boolean isNStraightHand(int[] hand, int m) {
Map<Integer, Integer> map = new HashMap<>();
PriorityQueue<Integer> q = new PriorityQueue<>((a,b)->a-b);
for (int i : hand) {
map.put(i, map.getOrDefault(i, 0) + 1);
q.add(i);
}
while (!q.isEmpty()) {
int t = q.poll();
if (map.get(t) == 0) continue;
for (int i = 0; i < m; i++) {
int cnt = map.getOrDefault(t + i, 0);
if (cnt == 0) return false;
map.put(t + i, cnt - 1);
}
}
return true;
}
}
C++ 代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class Solution {
public:
bool isNStraightHand(vector<int>& hand, int m) {
unordered_map<int, int> count;
priority_queue<int, vector<int>, greater<int>> pq;
for (int num : hand) {
count[num]++;
pq.push(num);
}
while (!pq.empty()) {
int t = pq.top();
pq.pop();
if (count[t] == 0) continue;
for (int i = 0; i < m; i++) {
if (count.find(t + i) == count.end() || count[t + i] == 0) return false;
count[t + i]--;
}
}
return true;
}
};
Python 代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Solution:
def isNStraightHand(self, hand: List[int], m: int) -> bool:
count = defaultdict(int)
for num in hand:
count[num] += 1
heapq.heapify(hand)
while hand:
t = heapq.heappop(hand)
if count[t] == 0:
continue
for i in range(m):
if count[t + i] <= 0:
return False
count[t + i] -= 1
return True
- 时间复杂度:令 $n$ 为数组
hand
长度,使用哈希表进行次数统计的复杂度为 $O(n)$;将所有元素从堆中存入和取出的复杂度为 $O(n\log{n})$。整体复杂度为 $O(n\log{n})$ - 空间复杂度:$O(n)$
最后
这是我们「刷穿 LeetCode」系列文章的第 No.846
篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!