2336. 无限集中的最小数字 : 容易又高效的分类做法

题目描述

这是 LeetCode 上的 2336. 无限集中的最小数字 ,难度为 中等

Tag : 「优先队列(堆)」、「哈希表」

现有一个包含所有正整数的集合 1 , 2 , 3 , 4 , 5 , . . . 1, 2, 3, 4, 5, ... 1,2,3,4,5,...

实现 SmallestInfiniteSet 类:

  • SmallestInfiniteSet() 初始化 SmallestInfiniteSet 对象以包含所有正整数。
  • int popSmallest() 移除并返回该无限集中的最小整数。
  • void addBack(int num) 如果正整数 num 不存在于无限集中,则将一个 num 添加到该无限集中。

示例:

scss 复制代码
输入
["SmallestInfiniteSet", "addBack", "popSmallest", "popSmallest", "popSmallest", "addBack", "popSmallest", "popSmallest", "popSmallest"]
[[], [2], [], [], [], [1], [], [], []]

输出
[null, null, 1, 2, 3, null, 1, 4, 5]

解释
SmallestInfiniteSet smallestInfiniteSet = new SmallestInfiniteSet();
smallestInfiniteSet.addBack(2);    // 2 已经在集合中,所以不做任何变更。
smallestInfiniteSet.popSmallest(); // 返回 1 ,因为 1 是最小的整数,并将其从集合中移除。
smallestInfiniteSet.popSmallest(); // 返回 2 ,并将其从集合中移除。
smallestInfiniteSet.popSmallest(); // 返回 3 ,并将其从集合中移除。
smallestInfiniteSet.addBack(1);    // 将 1 添加到该集合中。
smallestInfiniteSet.popSmallest(); // 返回 1 ,因为 1 在上一步中被添加到集合中,
                                   // 且 1 是最小的整数,并将其从集合中移除。
smallestInfiniteSet.popSmallest(); // 返回 4 ,并将其从集合中移除。
smallestInfiniteSet.popSmallest(); // 返回 5 ,并将其从集合中移除。

提示:

  • 1 < = n u m < = 1000 1 <= num <= 1000 1<=num<=1000
  • 最多调用 popSmallestaddBack 方法 共计 1000 1000 1000 次

优先队列(小根堆)+ 哈希表

使用 idx 代表顺序弹出的集合左边界, i d x , + ∞ idx, +\\infty idx,+∞ 范围内的数均为待弹出,起始有 i d x = 1 idx = 1 idx=1。

考虑当调用 addBack 往集合添加数值 x 时,该如何处理:

  • x ≥ i d x x \geq idx x≥idx:数值本身就存在于集合中,忽略该添加操作;
  • x = i d x − 1 x = idx - 1 x=idx−1:数值刚好位于边界左侧,更新 i d x = i d x − 1 idx = idx - 1 idx=idx−1;
  • x < i d x − 1 x < idx - 1 x<idx−1:考虑将数值添加到某个容器中,该容器支持返回最小值,容易联想到"小根堆";但小根堆并没有"去重"功能,为防止重复弹出,还需额外使用"哈希表"来记录哪些元素在堆中。

该做法本质上将集合分成两类:一类是从 idx 到正无穷的连续段,对此类操作的复杂度为 O ( 1 ) O(1) O(1);一类是比 idx 要小的离散类数集,对该类操作复杂度为 O ( log ⁡ n ) O(\log{n}) O(logn),其中 n n n 为调用 addBack 的最大次数。

Java 代码:

Java 复制代码
class SmallestInfiniteSet {
    boolean[] vis = new boolean[1010];
    PriorityQueue<Integer> q = new PriorityQueue<>((a,b)->a-b);
    int idx = 1;
    public int popSmallest() {
        int ans = -1;
        if (!q.isEmpty()) {
            ans = q.poll();
            vis[ans] = false;
        } else {
            ans = idx++;
        }
        return ans;
    }
    public void addBack(int x) {
        if (x >= idx || vis[x]) return ;
        if (x == idx - 1) {
            idx--;
        } else {
            q.add(x);
            vis[x] = true;
        }
    }
}

C++ 代码:

C++ 复制代码
class SmallestInfiniteSet {
public:
    vector<bool> vis;
    priority_queue<int, vector<int>, greater<int>> q;
    int idx;
    SmallestInfiniteSet() : idx(1) {
        vis.resize(1010, false);
    }
    int popSmallest() {
        int ans = -1;
        if (!q.empty()) {
            ans = q.top();
            q.pop();
            vis[ans] = false;
        } else {
            ans = idx++;
        }
        return ans;
    }
    void addBack(int x) {
        if (x >= idx || vis[x]) return;
        if (x == idx - 1) {
            idx--;
        } else {
            q.push(x);
            vis[x] = true;
        }
    }
};

Python 代码:

Python 复制代码
class SmallestInfiniteSet:
    def __init__(self):
        self.vis = [False] * 1010
        self.q = []
        self.idx = 1

    def popSmallest(self):
        ans = -1
        if self.q:
            ans = heapq.heappop(self.q)
            self.vis[ans] = False
        else:
            ans = self.idx
            self.idx += 1
        return ans

    def addBack(self, x):
        if x >= self.idx or self.vis[x]:
            return
        if x == self.idx - 1:
            self.idx -= 1
        else:
            heapq.heappush(self.q, x)
            self.vis[x] = True
  • 时间复杂度:插入和取出的最坏复杂度为 O ( log ⁡ n ) O(\log{n}) O(logn)
  • 空间复杂度: O ( n ) O(n) O(n)

最后

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

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

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

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

更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉

相关推荐
苏三说技术5 分钟前
如何看待GPT-6在UP主众测中碾压夺冠?它是现在最强大模型吗?
后端
mldong24 分钟前
一份 JSON,一条能跑的审批流:把报销流程送上工作流引擎
后端·架构
wno70426 分钟前
Spring Boot WebFlux增删改查
java·spring boot·后端
Captaincc29 分钟前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
醇氧1 小时前
MySQL 8.0 系统表损坏与引擎转换故障排查实战
数据结构·算法
大熊背1 小时前
《Color constancy by characterization of illumination chromaticity》之色度色域最大化算法(二)
算法·白平衡·色度·色温
钓鱼的肝1 小时前
梳理(1-5)
c++·经验分享·笔记·算法·青少年编程
aramae1 小时前
模拟实现strlen()函数 (C语言)
c语言·开发语言·后端
HZZD_HZZD2 小时前
CSDN_批发市场水电漏损归因算法LAM的原理与落地
嵌入式硬件·物联网·算法
计算机魔术师2 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端