Leetcode经典题9--O(1)时间的插入,添加和获取随机元素

题目描述:

实现RandomizedSet 类:

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

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

解题方案:

方式一:变长数组+哈希表

算法思想: 变长数组可以在 O(1) 的时间内完成获取随机元素操作,但是由于无法在 O(1) 的时间内判断元素是否存在,因此不能在 O(1) 的时间内完成插入和删除操作。哈希表可以在 O(1) 的时间内完成插入和删除操作,但是由于无法根据下标定位到特定元素,因此不能在 O(1) 的时间内完成获取随机元素操作。为了满足插入、删除和获取随机元素操作的时间复杂度都是 O(1),需要将变长数组和哈希表结合,变长数组中存储元素,哈希表中存储每个元素在变长数组中的下标。

插入操作时,首先判断 val 是否在哈希表中,如果已经存在则返回 false,如果不存在则插入 val,操作如下:

在变长数组的末尾添加 val;

在添加 val 之前的变长数组长度为 val 所在下标 index,将 val 和下标 index 存入哈希表;

返回 true。

**删除操作时,**首先判断 val 是否在哈希表中,如果不存在则返回 false,如果存在则删除 val,操作如下:

从哈希表中获得 val 的下标 index;

将变长数组的最后一个元素 last 移动到下标 index 处,在哈希表中将 last 的下标更新为 index;

在变长数组中删除最后一个元素,在哈希表中删除 val;

返回 true。

删除操作的重点在于将变长数组的最后一个元素移动到待删除元素的下标处,然后删除变长数组的最后一个元素。该操作的时间复杂度是 O(1),且可以保证在删除操作之后变长数组中的所有元素的下标都连续,方便插入操作和获取随机元素操作。

**获取随机元素操作时,**由于变长数组中的所有元素的下标都连续,因此随机选取一个下标,返回变长数组中该下标处的元素。

实现代码:

class RandomizedSet {
    List<Integer> nums;
    Map<Integer,Integer> indics;
    Random random;

    public RandomizedSet() {
        nums=new ArrayList<Integer>();
        indics=new HashMap<Integer,Integer>();
        random=new Random();
    }
    
    public boolean insert(int val) {
        if(indics.containsKey(val)){
            return false;
        }
        int index=nums.size();
        nums.add(val);
        indics.put(val,index);
        return true;
    }
    
    public boolean remove(int val) {
        if(!indics.containsKey(val)){
            return false;
        }
        int index=indics.get(val);
        int last=nums.get(nums.size()-1);
        nums.set(index,last);
        indics.put(last,index);
        nums.remove(nums.size()-1);
        indics.remove(val);
        return true;
    }
    
    public int getRandom() {
        int randomIndex=random.nextInt(nums.size());
        return nums.get(randomIndex);
    }
}
本题相关知识点
变长数组List 可以进行的相关操作

get(int index): 用于获取指定索引位置的元素。

例如,List list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); int element = list.get(1);,这里element的值为2。

set(int index, Integer element): 用于替换指定索引位置的元素,并返回被替换的元素。

例如,List list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); int oldElement = list.set(1, 4);,此时list变为[1, 4, 3],oldElement的值为2。

add(Integer element): 在列表的末尾添加一个元素。

例如,List list = new ArrayList<>(); list.add(1); list.add(2);,则list变为[1, 2]。

add(int index, Integer element): 在指定的索引位置插入一个元素,原索引位置及之后的元素向后移动一位。

例如,List list = new ArrayList<>(); list.add(1); list.add(3); list.add(1, 2);,则list变为[1, 2, 3]。

remove(int index): 删除指定索引位置的元素,并返回被删除的元素。

例如,List list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); int removedElement = list.remove(1);,此时list变为[1, 3],removedElement的值为2。

remove(Integer element): 删除列表中第一个出现的指定元素。

例如,List list = new ArrayList<>(); list.add(1); list.add(2); list.add(1); list.remove((Integer)1);,这里需要注意要将1转换为Integer类型,执行后list变为[2, 1]。

indexOf(Integer element): 返回指定元素在列表中第一次出现的索引,如果不存在则返回-1。

例如,List list = new ArrayList<>(); list.add(1); list.add(2); list.add(1); int index = list.indexOf(1);,index的值为0。

lastIndexOf(Integer element): 返回指定元素在列表中最后一次出现的索引,如果不存在则返回-1。

例如,List list = new ArrayList<>(); list.add(1); list.add(2); list.add(1); int index = list.lastIndexOf(1);,index的值为2。

contains(Integer element): 判断列表是否包含指定元素,返回true或false。

例如,List list = new ArrayList<>(); list.add(1); list.add(2); boolean result = list.contains(1);,result的值为true。

**size():**返回列表中元素的个数。例如,List list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); int size = list.size();,size的值为3。

**isEmpty():**判断列表是否为空,返回true或false。例如,List list = new ArrayList<>(); boolean result = list.isEmpty();,result的值为true。

subList(int fromIndex, int toIndex): 返回一个包含指定范围元素的子列表,左闭右开区间。例如,List list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); List subList = list.subList(0, 2);,subList为[1, 2]。

哈希表Map可以进行的相关操作

put(Integer key, Integer value): 将指定的键值对添加到Map中,如果键已存在,则用新的值替换旧的值,并返回旧的值。

get(Integer key): 根据指定的键获取对应的值,如果键不存在,则返回null。

getOrDefault(Integer key, Integer defaultValue): 根据指定的键获取对应的值,如果键不存在,则返回默认值。

remove(Integer key): 根据指定的键删除对应的键值对,并返回被删除的值,如果键不存在,则返回null。

keySet(): 返回Map中所有键的集合,可以通过遍历键集来获取对应的值。

values(): 返回Map中所有值的集合。

entrySet(): 返回Map中所有键值对的集合,每个键值对是一个Map.Entry对象,可以通过该对象获取键和值。

**size():**返回Map中键值对的数量。

**isEmpty():**判断Map是否为空,返回true或false。

containsKey(Integer key): 判断Map中是否包含指定的键,返回true或false。

containsValue(Integer value): 判断Map中是否包含指定的值,返回true或false。

相关推荐
Coovally AI模型快速验证35 分钟前
MMYOLO:打破单一模式限制,多模态目标检测的革命性突破!
人工智能·算法·yolo·目标检测·机器学习·计算机视觉·目标跟踪
可为测控1 小时前
图像处理基础(4):高斯滤波器详解
人工智能·算法·计算机视觉
Milk夜雨2 小时前
头歌实训作业 算法设计与分析-贪心算法(第3关:活动安排问题)
算法·贪心算法
BoBoo文睡不醒2 小时前
动态规划(DP)(细致讲解+例题分析)
算法·动态规划
apz_end3 小时前
埃氏算法C++实现: 快速输出质数( 素数 )
开发语言·c++·算法·埃氏算法
仟濹3 小时前
【贪心算法】洛谷P1106 - 删数问题
c语言·c++·算法·贪心算法
银河梦想家4 小时前
【Day23 LeetCode】贪心算法题
leetcode·贪心算法
CM莫问4 小时前
python实战(十五)——中文手写体数字图像CNN分类
人工智能·python·深度学习·算法·cnn·图像分类·手写体识别
sz66cm4 小时前
LeetCode刷题 -- 45.跳跃游戏 II
算法·leetcode
Amor风信子4 小时前
华为OD机试真题---战场索敌
java·开发语言·算法·华为od·华为