846. 一手顺子 : 数据结构模拟题

题目描述

这是 LeetCode 上的 846. 一手顺子 ,难度为 中等

Tag : 「模拟」、「优先队列」、「哈希表」

Alice 手中有一把牌,她想要重新排列这些牌,分成若干组,使每一组的牌数都是 groupSize ,并且由 groupSize 张连续的牌组成。

给你一个整数数组 hand 其中 hand[i] 是写在第 i 张牌,和一个整数 groupSize

如果她可能重新排列这些牌,返回 true ;否则,返回 false

示例 1:

输入:hand = [1,2,3,6,2,3,4,7,8], groupSize = 3

输出:true

解释:Alice 手中的牌可以被重新排列为 [1,2,3],[2,3,4],[6,7,8]。
复制代码

示例 2:

输入:hand = [1,2,3,4,5], groupSize = 4

输出:false

解释:Alice 手中的牌无法被重新排列成几个大小为 4 的组。
复制代码

提示:

  • 1 < = h a n d . l e n g t h < = 1 0 4 1 <= hand.length <= 10^4
  • 0 < = h a n d [ i ] < = 1 0 9 0 <= hand[i] <= 10^9
  • 1 < = g r o u p S i z e < = h a n d . l e n g t h 1 <= groupSize <= hand.length

模拟 + 哈希表 + 优先队列(堆)

为了方便,我们令 m = g r o u p S i z e m = groupSize

题目要求我们将 h a n d hand 分为若干份大小为 m m 的顺子。

在给定 h a n d hand 的情况下,划分方式唯一确定,因此本质上这是一个「模拟」的过程。

具体的,我们可以使用「哈希表」对 h a n d hand 中的数值进行「出现次数」统计,并用于后续 实时 维护剩余元素的出现次数。

然后使用优先队列维护(小根堆)所有的 h a n d [ i ] hand[i] 。每次从优先队列(堆)中取出堆顶元素 t t 尝试作为「顺子」的发起点/首个元素(当然 t t 能够作为发起点的前提是 t t 仍是剩余元素,即实时维护的出现次数不为 0 0 ),然后用 t t 作为发起点/首个元素构造顺子,即对 [ t , t + 1 , . . . , t + m 1 ] [t, t + 1, ... , t + m - 1] 元素的出现次数进行 1 -1 操作。

若构造过程中没有出现「剩余元素出现次数」不足以 1 -1 的话,说明整个构造过程没有冲突,返回 True,否则返回 False

代码:

class 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;
    }
}
复制代码
  • 时间复杂度:令 n n 为数组 hand 长度,使用哈希表进行次数统计的复杂度为 O ( n ) O(n) ;将所有元素从堆中存入和取出的复杂度为 O ( n log n ) O(n\log{n}) 。整体复杂度为 O ( n log n ) O(n\log{n})
  • 空间复杂度: O ( n ) O(n)

最后

这是我们「刷穿 LeetCode」系列文章的第 No.846 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。

为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour…

在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

猜你喜欢

转载自juejin.im/post/7047267989950824479