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

简介: 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 <= hand.length <= 10^41<=hand.length<=104
  • 0 <= hand[i] <= 10^90<=hand[i]<=109
  • 1 <= groupSize <= hand.length1<=groupSize<=hand.length


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



为了方便,我们令 m = groupSizem=groupSize


题目要求我们将 handhand 分为若干份大小为 mm 的顺子。


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


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


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


若构造过程中没有出现「剩余元素出现次数」不足以 -11 的话,说明整个构造过程没有冲突,返回 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;
    }
}
复制代码


  • 时间复杂度:令 nn 为数组 hand 长度,使用哈希表进行次数统计的复杂度为 O(n)O(n);将所有元素从堆中存入和取出的复杂度为 O(n\log{n})O(nlogn)。整体复杂度为 O(n\log{n})O(nlogn)
  • 空间复杂度:O(n)O(n)


最后



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


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


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


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

相关文章
【CCCC】L2-032 彩虹瓶 (25分),模拟题,出栈顺序
【CCCC】L2-032 彩虹瓶 (25分),模拟题,出栈顺序
200 0
385. 迷你语法分析器 : 栈运用模拟题
385. 迷你语法分析器 : 栈运用模拟题
|
机器学习/深度学习 存储 算法
2034. 股票价格波动 : 数据结构模拟题
2034. 股票价格波动 : 数据结构模拟题
|
存储 机器学习/深度学习
【刷穿 LeetCode】1583. 统计不开心的朋友 : 数据结构模拟题
【刷穿 LeetCode】1583. 统计不开心的朋友 : 数据结构模拟题
|
存储 算法 Java
【每日算法】数据结构运用模拟题(双栈表达式计算的简化版) |Python 主题月
【每日算法】数据结构运用模拟题(双栈表达式计算的简化版) |Python 主题月
|
存储 算法 Python
【每日算法】数据结构运用模拟题 |Python 主题月
【每日算法】数据结构运用模拟题 |Python 主题月
|
11月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
229 59
|
4月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
63 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。