代码训练LeetCode(23)随机访问元素

news2025/6/7 2:37:48

代码训练(23)LeetCode之随机访问元素

Author: Once Day Date: 2025年6月5日

漫漫长路,才刚刚开始…

全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客

参考文章:

  • 380. O(1) 时间插入、删除和获取随机元素 - 力扣(LeetCode)
  • 力扣 (LeetCode) 全球极客挚爱的技术成长平台

文章目录

      • 代码训练(23)LeetCode之随机访问元素
        • 1. 原题
        • 2. 分析
        • 3. 代码实现
        • 4. 总结

1. 原题

实现RandomizedSet 类:

  • RandomizedSet() 初始化 RandomizedSet 对象
  • bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false
  • bool remove(int val) 当元素 val 存在时,从集合中移除该项,并返回 true ;否则,返回 false
  • int getRandom() 随机返回现有集合中的一项(测试用例保证调用此方法时集合中至少存在一个元素)。每个元素应该有 相同的概率 被返回。

你必须实现类的所有函数,并满足每个函数的 平均 时间复杂度为 O(1)

提示:

  • -231 <= val <= 231 - 1
  • 最多调用 insertremovegetRandom 函数 2 * ``105
  • 在调用 getRandom 方法时,数据结构中 至少存在一个 元素。

示例 1:

输入
["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
输出
[null, true, false, true, 2, true, false, 2]

解释
RandomizedSet randomizedSet = new RandomizedSet();
randomizedSet.insert(1); // 向集合中插入 1 。返回 true 表示 1 被成功地插入。
randomizedSet.remove(2); // 返回 false ,表示集合中不存在 2 。
randomizedSet.insert(2); // 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。
randomizedSet.getRandom(); // getRandom 应随机返回 1 或 2 。
randomizedSet.remove(1); // 从集合中移除 1 ,返回 true 。集合现在包含 [2] 。
randomizedSet.insert(2); // 2 已在集合中,所以返回 false 。
randomizedSet.getRandom(); // 由于 2 是集合中唯一的数字,getRandom 总是返回 2 。
2. 分析

题目要求实现一个 RandomizedSet 类,该类包含以下方法:

  1. RandomizedSet() - 初始化对象。
  2. bool insert(int val) - 插入元素 val,如果元素不存在则插入并返回 true,否则返回 false
  3. bool remove(int val) - 移除元素 val,如果元素存在则移除并返回 true,否则返回 false
  4. int getRandom() - 随机返回集合中的一个元素。保证调用时集合中至少有一个元素,且每个元素有相同的被返回概率。

要求所有操作的平均时间复杂度为 O(1)。

为了满足该题目的要求,我们可以使用哈希表和数组组合的数据结构:

  1. 数组:用于存储元素,支持 O(1) 时间复杂度的随机访问。
  2. 哈希表:键为元素值,值为该元素在数组中的索引,支持 O(1) 时间复杂度的插入和删除操作。

方法实现细节:

插入 (insert):

  • 检查哈希表中是否已存在该元素。如果存在,返回 false
  • 将元素添加到数组末尾,并在哈希表中记录该元素的索引。
  • 返回 true

删除 (remove):

  • 检查哈希表中是否存在该元素。如果不存在,返回 false
  • 从数组中移除该元素,为了维持 O(1) 的复杂度,可以将数组最后一个元素移动到被删除元素的位置,并更新哈希表。
  • 从哈希表中删除该元素,并更新数组的大小。
  • 返回 true

获取随机元素 (getRandom):

  • 从数组中随机选择一个索引,然后返回该索引对应的元素。

性能优化关键点:

  • 内存管理:合理分配和释放内存是关键,尤其是在 randomizedSetCreaterandomizedSetFree 函数中。
  • 哈希冲突:避免哈希冲突可以提升性能,因此选择合适的哈希函数和冲突解决机制很重要。
3. 代码实现
struct entry {
    int val;
    int idx;
    struct entry* next;
};

typedef struct {
    int size;                  // 当前元素数量
    int array[200000];         // 动态数组存储元素
    struct entry* map[100000]; // 哈希表存储元素到索引的映射
} RandomizedSet;

RandomizedSet* randomizedSetCreate() {
    RandomizedSet* set = malloc(sizeof(RandomizedSet));
    memset(set, 0x0, sizeof(RandomizedSet));
    srand(time(NULL)); // 初始化随机种子
    return set;
}

bool randomizedSetInsert(RandomizedSet* set, int val) {
    int key = val % 100000;
    struct entry** prev = &(set->map[key]);
    struct entry* item = set->map[key];
    while (item != NULL) {
        if (item->val == val) {
            return false;
        }
        prev = &(item->next);
        item = item->next;
    }

    item = malloc(sizeof(struct entry));
    item->val = val;
    item->next = NULL;
    item->idx = set->size;
    *prev = item;

    set->array[set->size] = val;
    set->size++;
    return true;
}

bool randomizedSetRemove(RandomizedSet* set, int val) {
    int key = val % 100000;
    struct entry** prev = &(set->map[key]);
    struct entry* item = set->map[key];
    while (item != NULL) {
        if (item->val == val) {
            break;
        }
        prev = &(item->next);
        item = item->next;
    }

    if (item == NULL) {
        return false;
    }

    *prev = item->next;
    int idx = item->idx;

    free(item);

    if (idx == set->size - 1) {
        set->size--;
        return true;
    }

    int lastElement = set->array[set->size - 1];
    set->array[idx] = lastElement; // 将最后一个元素移动到被删除元素的位置
    set->size--;

    key = lastElement % 100000;
    item = set->map[key];
    while (item != NULL) {
        if (item->val == lastElement) {
            break;
        }
        item = item->next;
    }

    item->idx = idx;

    return true;
}

int randomizedSetGetRandom(RandomizedSet* set) {
    int randomIndex = rand() % set->size;
    return set->array[randomIndex];
}

void randomizedSetFree(RandomizedSet* set) {
    for (int i = 0; i < 100000; i++) {
        struct entry* item = set->map[i];
        while (item != NULL) {
            struct entry* temp = item->next;
            free(item);
            item = temp;
        }
    }

    free(set);
}

这段代码实现了一个 RandomizedSet 结构,它支持插入、删除、随机访问和销毁操作。下面分析每部分代码的功能和设计逻辑。

使用了两种数据结构:

  • 数组 (array):用于存储元素值,支持快速通过索引访问和随机访问。
  • 哈希表 (map):链地址法解决哈希冲突的哈希表,存储键为元素值,值为该元素在数组中的索引。

分配内存并初始化 RandomizedSet,其中 memset 用于初始化内存区域。

插入操作首先计算哈希键值,然后遍历链表检查元素是否已存在。如果不存在,创建新条目并加入链表和数组。

删除操作查找链表中的元素,然后从链表和数组中删除,同时更新相关元素的索引。

通过随机生成索引来从数组中获取元素。

释放哈希表中所有链表的内存以及 RandomizedSet 结构的内存。

4. 总结

这个题目主要考察数据结构的灵活应用和操作的优化。通过综合利用数组和哈希表,我们能够实现各种操作的平均 O(1) 时间复杂度。对于提升编程能力,重点是掌握各种数据结构的特点及其适用场景,以及如何根据需求选择和设计最合适的数据结构。

表和数组中删除,同时更新相关元素的索引。

通过随机生成索引来从数组中获取元素。

释放哈希表中所有链表的内存以及 RandomizedSet 结构的内存。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2402364.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【R语言编程绘图-plotly】

安装与加载 在R中使用plotly库前需要安装并加载。安装可以通过CRAN进行&#xff0c;使用install.packages()函数。加载库使用library()函数。 install.packages("plotly") library(plotly)测试库文件安装情况 # 安装并加载必要的包 if (!requireNamespace("p…

通信刚需,AI联手ethernet/ip转profinet网关打通工业技术难关

工业人工智能&#xff1a;食品和饮料制造商的实际用例通信刚需 了解食品饮料制造商如何利用人工智能克服业务挑战 食品和饮料制造商正面临劳动力短缺、需求快速变化、运营复杂性加剧以及通胀压力等挑战。如今&#xff0c;生产商比以往任何时候都更需要以更少的投入实现更高的…

JavaEE->多线程:定时器

定时器 约定一个时间&#xff0c;时间到了&#xff0c;执行某个代码逻辑&#xff08;进行网络通信时常见&#xff09; 客户端给服务器发送请求 之后就需要等待 服务器的响应&#xff0c;客户端不可能无限的等&#xff0c;需要一个最大的期限。这里“等待的最大时间”可以用定时…

<el-table>构建树形结构

最佳实践 el-table实现树形结构主要依靠row-key和tree-props来实现的。 &#x1f4ab; 无论是el-table实现的树形结构还是el-tree组件都是绑定的树形结构的数据&#xff0c;因此如果数据是扁平的话&#xff0c;需要进行树化。 代码 <template><div><el-table:d…

linux——磁盘和文件系统管理

1、磁盘基础简述 1.1 硬盘基础知识 硬盘&#xff08;Hard Disk Drive&#xff0c;简称 HDD&#xff09;是计算机常用的存储设备之一. p如果从存储数据的介质上来区分&#xff0c;硬盘可分为机械硬盘&#xff08;Hard Disk Drive, HDD&#xff09;和固态硬盘&#xff08;Soli…

云原生 DevOps 实践路线:构建敏捷、高效、可观测的交付体系

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、引言&#xff1a;DevOps 与云原生的深度融合 在传统软件工程范式下&#xff0c;开发与运维之间存在天然的壁垒。开发希望尽快…

gateway 网关 路由新增 (已亲测)

问题&#xff1a; 前端通过gateway调用后端接口&#xff0c;路由转发失败&#xff0c;提示404 not found 排查&#xff1a; 使用 { "href":"/actuator/gateway/routes", "methods":[ "POST", "GET" ] } 命令查看路由列表&a…

Python 训练营打卡 Day 33-神经网络

简单神经网络的流程 1.数据预处理&#xff08;归一化、转换成张量&#xff09; 2.模型的定义 继承nn.Module类 定义每一个层 定义前向传播流程 3.定义损失函数和优化器 4.定义训练过程 5.可视化loss过程 预处理补充&#xff1a; 分类任务中&#xff0c;若标签是整…

如何有效删除 iPhone 上的所有内容?

“在出售我的 iPhone 之前&#xff0c;我该如何清除它&#xff1f;我担心如果我卖掉它&#xff0c;有人可能会从我的 iPhone 中恢复我的信息。” 升级到新 iPhone 后&#xff0c;你如何处理旧 iPhone&#xff1f;你打算出售、以旧换新还是捐赠&#xff1f;无论你选择哪一款&am…

AI大模型学习三十二、飞桨AI studio 部署 免费Qwen3-235B与Qwen3-32B,并导入dify应用

一、说明 ‌Qwen3-235B 和 Qwen3-32B 的主要区别在于它们的参数规模和应用场景。‌ 参数规模 ‌Qwen3-235B‌&#xff1a;总参数量为2350亿&#xff0c;激活参数量为220亿‌。‌Qwen3-32B‌&#xff1a;总参数量为320亿‌。 应用场景 ‌Qwen3-235B‌&#xff1a;作为旗舰模型&a…

操作系统中的设备管理,Linux下的I/O

1. I/O软件分层 I/O 层次结构分为五层&#xff1a; 用户层 I/O 软件设备独立性软件设备驱动程序中断处理程序硬件 其中&#xff0c;设备独立性软件、设备驱动程序、中断处理程序属于操作系统的内核部分&#xff0c;即“I/O 系统”&#xff0c;或称“I/O 核心子系统”。 2.用…

LabVIEW与Modbus/TCP温湿度监控系统

基于LabVIEW 开发平台与 Modbus/TCP 通信协议&#xff0c;设计一套适用于实验室环境的温湿度数据采集监控系统。通过上位机与高精度温湿度采集设备的远程通信&#xff0c;实现多设备温湿度数据的实时采集、存储、分析及报警功能&#xff0c;解决传统人工采集效率低、环境适应性…

Cursor 1.0 版本 GitHub MCP 全面指南:从安装到工作流增强

Cursor 1.0 版本 GitHub MCP 全面指南:从安装到工作流增强 简介 GitHub MCP (Machine Coding Protocol) 是一种强大的工具,能够自动化代码生成、管理和分析,从而显著提升开发效率。本文将全面介绍 GitHub MCP 的安装、配置、使用以及如何将其融入您的工作流。 本文介绍两种…

自主设计一个DDS信号发生器

DDS发生器 DDS信号发生器是直接数字频率合成技术&#xff0c;采用直接数字频率合成(Direct Digital Synthesis&#xff0c;简称DDS)技术&#xff0c;把信号发生器的频率稳定度、准确度提高到与基准频率相同的水平&#xff0c;并且可以在很宽的频率范围内进行精细的频率调节。采…

鸿蒙UI(ArkUI-方舟UI框架)- 使用弹框

返回主章节 → 鸿蒙UI&#xff08;ArkUI-方舟UI框架&#xff09; 文章目录 弹框概述使用弹出框(Dialog)弹出框概述不依赖UI组件的全局自定义弹出框(openCustomDialog)(推荐)生命周期自定义弹出框的打开与关闭更新自定义弹出框内容更新自定义弹出框的属性完整示例 基础自定义弹…

学习笔记(24): 机器学习之数据预处理Pandas和转换成张量格式[2]

学习笔记(24): 机器学习之数据预处理Pandas和转换成张量格式[2] 学习机器学习&#xff0c;需要学习如何预处理原始数据&#xff0c;这里用到pandas&#xff0c;将原始数据转换为张量格式的数据。 学习笔记(23): 机器学习之数据预处理Pandas和转换成张量格式[1]-CSDN博客 下面…

在不同型号的手机或平板上后台运行Aidlux

在不同型号的手机或平板上后台运行Aidlux 一、鸿蒙/HarmonyOS手机与平板 二、小米手机与平板 三、OPPO手机与平板 四、vivo手机与平板 一、鸿蒙/HarmonyOS手机与平板 &#xff08;系统版本有差异&#xff0c;但操作原理相通&#xff09; 第一步&#xff1a;点击设置——应用和…

【SSM】SpringBoot学习笔记1:SpringBoot快速入门

前言&#xff1a; 文章是系列学习笔记第9篇。基于黑马程序员课程完成&#xff0c;是笔者的学习笔记与心得总结&#xff0c;供自己和他人参考。笔记大部分是对黑马视频的归纳&#xff0c;少部分自己的理解&#xff0c;微量ai解释的内容&#xff08;ai部分会标出&#xff09;。 …

1.企业可观测性监控三大支柱及开源方案的横评对比

[ 知识是人生的灯塔&#xff0c;只有不断学习&#xff0c;才能照亮前行的道路 ] &#x1f4e2; 大家好&#xff0c;我是 WeiyiGeek&#xff0c;一名深耕安全运维开发&#xff08;SecOpsDev&#xff09;领域的技术从业者&#xff0c;致力于探索DevOps与安全的融合&#xff08;De…

双空间知识蒸馏用于大语言模型

Dual-Space Knowledge Distillation for Large Language Models 发表&#xff1a;EMNLP 2024 机构&#xff1a;Beijing Key Lab of Traffic Data Analysis and Mining 连接&#xff1a;https://aclanthology.org/2024.emnlp-main.1010.pdf 代码&#xff1a;GitHub - songmz…