JavaInterview JavaInterview
首页
指南
分类
标签
归档
  • CSDN (opens new window)
  • 文档集合 (opens new window)
  • 系统架构 (opens new window)
  • 微信号 (opens new window)
  • 公众号 (opens new window)

『Java面试+Java学习』
首页
指南
分类
标签
归档
  • CSDN (opens new window)
  • 文档集合 (opens new window)
  • 系统架构 (opens new window)
  • 微信号 (opens new window)
  • 公众号 (opens new window)
  • 指南
  • 简历

  • Java

  • 面试

  • 算法

  • algorithm
  • leetcode
JavaInterview.cn
2022-06-17
目录

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

文章发布较早,内容可能过时,阅读注意甄别。

# 题目

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);// 向集合中插入 1 。返回 true 表示集合不包含 1 。
collection.insert(1);// 向集合中插入另一个 1 。返回 false 表示集合包含 1 。集合现在包含 [1,1] 。
collection.insert(2);// 向集合中插入 2 ,返回 true 。集合现在包含 [1,1,2] 。
collection.getRandom();// getRandom 应当有 2/3 的概率返回 1 ,1/3 的概率返回 2 。
collection.remove(1);// 从集合中删除 1 ,返回 true 。集合现在包含 [1,2] 。
collection.getRandom();// getRandom 应有相同概率返回 1 和 2 。
 

提示:

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

# 思路

/**
 * O(1)获取、插入、删除。
 * 1.获取是只要一个合法的下标,对有序列表的获取即为 O(1)
 * 2.插入操作由于 List 是尾插法,也是 O(1)
 * 3.删除操作只有删除 list 的最后一个元素的时候是 O(1)
 * 除此之位,因为插入和删除操作涉及到是否重复的返回,相当于要在 O(1) 时间做遍历的检查,因此需要额外的哈希类型数据结构,采用 Map 存储 <元素,出现位置>
 */

# 解法


/**
 * O(1)获取、插入、删除。
 * 1.获取是只要一个合法的下标,对有序列表的获取即为 O(1)
 * 2.插入操作由于 List 是尾插法,也是 O(1)
 * 3.删除操作只有删除 list 的最后一个元素的时候是 O(1)
 * 除此之位,因为插入和删除操作涉及到是否重复的返回,相当于要在 O(1) 时间做遍历的检查,因此需要额外的哈希类型数据结构,采用 Map 存储 <元素,出现位置>
 */
class RandomizedCollection {
    private List<Integer> nums;//存储 val 元素
    private Map<Integer, Set<Integer>> map;//存储每个 val 的下标集合
    public RandomizedCollection() {
        nums = new ArrayList();
        map = new HashMap();
    }
    
    public boolean insert(int val) {
        nums.add(val);//元素列表直接添加到末尾,O(1)
        Set<Integer> set = map.getOrDefault(val, new HashSet<Integer>());
        set.add(nums.size() - 1);//set里加入下标,O(1)
        map.put(val, set);
        return set.size() == 1;//返回是否重复,即set里存了多少个 val 对应的下标,O(1)
    }

    public boolean remove(int val) {
        if(!map.containsKey(val))return false;
        //获取一个 val 值对应的下标,hash操作,为O(1)
        Iterator<Integer> it = map.get(val).iterator();
        int i = it.next();
        //获取列表尾部元素,并换到 val 的位置
        int lastNum = nums.get(nums.size() - 1);
        nums.set(i, lastNum);
        //删除 val 的位置,尾部元素的位置
        map.get(val).remove(i);
        map.get(lastNum).remove(nums.size() - 1);
        //更新尾部元素的下标集合
        if(i < nums.size() - 1)map.get(lastNum).add(i);
        if(map.get(val).size() == 0)map.remove(val);//如果val只出现一次,直接删除他的下标集合
        nums.remove(nums.size() - 1);
        return true;
    }
    
    public int getRandom() {
        return nums.get((int)(Math.random() * nums.size()));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 总结

  • 分析出几种情况,然后分别对各个情况实现
微信 支付宝
最近更新
01
1686. 石子游戏VI Java
08-18
02
1688. 比赛中的配对次数 Java
08-18
03
1687. 从仓库到码头运输箱子 Java
08-18
更多文章>
Theme by Vdoing | Copyright © 2019-2025 JavaInterview.cn
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式