【哈希映射】【 哈希集合】 381. O(1) 时间插入、删除和获取随机元素 - 允许重复

本文主要是介绍【哈希映射】【 哈希集合】 381. O(1) 时间插入、删除和获取随机元素 - 允许重复,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者推荐

视频算法专题

本文涉及知识点

哈希映射 哈希集合

LeetCode 381. O(1) 时间插入、删除和获取随机元素 - 允许重复

RandomizedCollection 是一种包含数字集合(可能是重复的)的数据结构。它应该支持插入和删除特定元素,以及删除随机元素。
实现 RandomizedCollection 类:
RandomizedCollection()初始化空的 RandomizedCollection 对象。
bool insert(int val) 将一个 val 项插入到集合中,即使该项已经存在。如果该项不存在,则返回 true ,否则返回 false 。
bool remove(int val) 如果存在,从集合中移除一个 val 项。如果该项存在,则返回 true ,否则返回 false 。注意,如果 val 在集合中出现多次,我们只删除其中一个。
int getRandom() 从当前的多个元素集合中返回一个随机元素。每个元素被返回的概率与集合中包含的相同值的数量 线性相关 。
您必须实现类的函数,使每个函数的 平均 时间复杂度为 O(1) 。
注意:生成测试用例时,只有在 RandomizedCollection 中 至少有一项 时,才会调用 getRandom 。
示例 1:
输入
[“RandomizedCollection”, “insert”, “insert”, “insert”, “getRandom”, “remove”, “getRandom”]
[[], [1], [1], [2], [], [1], []]
输出
[null, true, false, true, 2, true, 1]

解释
RandomizedCollection collection = new RandomizedCollection();// 初始化一个空的集合。
collection.insert(1); // 返回 true,因为集合不包含 1。
// 将 1 插入到集合中。
collection.insert(1); // 返回 false,因为集合包含 1。
// 将另一个 1 插入到集合中。集合现在包含 [1,1]。
collection.insert(2); // 返回 true,因为集合不包含 2。
// 将 2 插入到集合中。集合现在包含 [1,1,2]。
collection.getRandom(); // getRandom 应当:
// 有 2/3 的概率返回 1,
// 1/3 的概率返回 2。
collection.remove(1); // 返回 true,因为集合包含 1。
// 从集合中移除 1。集合现在包含 [1,2]。
collection.getRandom(); // getRandom 应该返回 1 或 2,两者的可能性相同。

提示:
-231 <= val <= 231 - 1
insert, remove 和 getRandom 最多 总共 被调用 2 * 105
当调用 getRandom 时,数据结构中 至少有一个 元素

哈希

用向量记录值,追加的时候时间复杂度是O1),删除是O(n)。可以将要删除的元素和尾元素互换,然后删除。
unordered_map<int, unordered_set> m_valueIndex; 记录各值在m_nums中的下标。
注意
要删除的元素就是末尾,要特殊处理。否则会删除下标失败,而多一个下标。

代码

核心代码

class RandomizedCollection {
public:RandomizedCollection() {srand(time(nullptr));std::cout << "==" << std::endl;}bool insert(int val) {bool b = m_valueIndex[val].empty();m_valueIndex[val].emplace(m_nums.size());m_nums.emplace_back(val);std::cout << m_nums.size() << std::endl;return b;}bool remove(int val) {if (m_valueIndex[val].empty()){return false;}const int delIndex = *m_valueIndex[val].begin();m_valueIndex[val].erase(m_valueIndex[val].begin());const int endValue = m_nums.back();if (m_valueIndex[endValue].count(m_nums.size() - 1)){m_valueIndex[endValue].erase(m_nums.size() - 1);m_valueIndex[endValue].emplace(delIndex);m_nums[delIndex] = endValue;}m_nums.pop_back();std::cout << "del " << m_nums.size() << std::endl;return true;}int getRandom() {std::cout << "getRandom " << m_nums.size() << std::endl;return m_nums[rand() % m_nums.size()];}unordered_map<int, unordered_set<int>> m_valueIndex;vector<int> m_nums;
};

2023年5月

class RandomizedCollection {
public:
RandomizedCollection() {
srand(time(nullptr));
}
bool insert(int val) {
m_mValueIndexs[val].emplace(m_iSize);
m_arr[m_iSize] = val;
m_iSize++;
return 1 == m_mValueIndexs[val].size();
}
bool remove(int val) {
if (m_mValueIndexs.count(val))
{
int index = *m_mValueIndexs[val].begin();
m_mValueIndexs[val].erase(index);
Erase(index);
if (m_mValueIndexs[val].empty())
{
m_mValueIndexs.erase(val);
}
return true;
}
return false;
}
int getRandom() {
int index = rand() % m_iSize;
return m_arr[index];
}
void Erase(int index)
{
if (m_iSize - 1 == index)
{
m_iSize–;
return;
}
const int iEndValue = m_arr[m_iSize - 1];
m_mValueIndexs[iEndValue].erase(m_iSize - 1);
m_mValueIndexs[iEndValue].insert(index);
std::swap(m_arr[m_iSize - 1], m_arr[index]);
m_iSize–;
}
std::unordered_map<int, std::unordered_set> m_mValueIndexs;
int m_arr[1000 * 200];
int m_iSize = 0;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 **C+

+17**
如无特殊说明,本算法用**C++**实现。

这篇关于【哈希映射】【 哈希集合】 381. O(1) 时间插入、删除和获取随机元素 - 允许重复的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/807760

相关文章

C++中RAII资源获取即初始化

《C++中RAII资源获取即初始化》RAII通过构造/析构自动管理资源生命周期,确保安全释放,本文就来介绍一下C++中的RAII技术及其应用,具有一定的参考价值,感兴趣的可以了解一下... 目录一、核心原理与机制二、标准库中的RAII实现三、自定义RAII类设计原则四、常见应用场景1. 内存管理2. 文件操

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

SpringBoot服务获取Pod当前IP的两种方案

《SpringBoot服务获取Pod当前IP的两种方案》在Kubernetes集群中,SpringBoot服务获取Pod当前IP的方案主要有两种,通过环境变量注入或通过Java代码动态获取网络接口IP... 目录方案一:通过 Kubernetes Downward API 注入环境变量原理步骤方案二:通过

从基础到进阶详解Pandas时间数据处理指南

《从基础到进阶详解Pandas时间数据处理指南》Pandas构建了完整的时间数据处理生态,核心由四个基础类构成,Timestamp,DatetimeIndex,Period和Timedelta,下面我... 目录1. 时间数据类型与基础操作1.1 核心时间对象体系1.2 时间数据生成技巧2. 时间索引与数据

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

C#之List集合去重复对象的实现方法

《C#之List集合去重复对象的实现方法》:本文主要介绍C#之List集合去重复对象的实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C# List集合去重复对象方法1、测试数据2、测试数据3、知识点补充总结C# List集合去重复对象方法1、测试数据

使用Python实现获取屏幕像素颜色值

《使用Python实现获取屏幕像素颜色值》这篇文章主要为大家详细介绍了如何使用Python实现获取屏幕像素颜色值,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 一、一个小工具,按住F10键,颜色值会跟着显示。完整代码import tkinter as tkimport pyau

Nginx Location映射规则总结归纳与最佳实践

《NginxLocation映射规则总结归纳与最佳实践》Nginx的location指令是配置请求路由的核心机制,其匹配规则直接影响请求的处理流程,下面给大家介绍NginxLocation映射规则... 目录一、Location匹配规则与优先级1. 匹配模式2. 优先级顺序3. 匹配示例二、Proxy_pa

python获取cmd环境变量值的实现代码

《python获取cmd环境变量值的实现代码》:本文主要介绍在Python中获取命令行(cmd)环境变量的值,可以使用标准库中的os模块,需要的朋友可以参考下... 前言全局说明在执行py过程中,总要使用到系统环境变量一、说明1.1 环境:Windows 11 家庭版 24H2 26100.4061

Python中bisect_left 函数实现高效插入与有序列表管理

《Python中bisect_left函数实现高效插入与有序列表管理》Python的bisect_left函数通过二分查找高效定位有序列表插入位置,与bisect_right的区别在于处理重复元素时... 目录一、bisect_left 基本介绍1.1 函数定义1.2 核心功能二、bisect_left 与