力扣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 时,数据结构中 至少有一个元素

思路:使用hashmap和list联合操作,hashmap存的是集合的值和该值在list中的索引集合,同时定义一个random类用于后续随机获取,n用于记录list元素个数,调用 RandomizedCollection就是初始化刚才的几个东西,然后插入操作的话就是把值加入到list中,加入到map中同时把索引值加到一个集合中,map存值和值对应得索引集合,n++,最后只需返回该值的索引集合大小是否为1就可以知道是否已经在集合中出现过,对于删除操作,如果map没有相应的key就直接返回false,如果map有相应的key的话就要考虑一个事,因为值是存在了list中,list只有删除最后一个元素是O(1)的,所以我们考虑将要删除的值和最后一个值做交换再删除,要删除map和list两处地方,并且删除完后还要更新最后一个元素的索引集合,更新n,对于随机获取元素操作就直接list.get一个random类生成的n范围内随机数字就好

class RandomizedCollection {

    Map<Integer,Set> index;
    List<Integer> list;
    Random random;
    int n;
    public RandomizedCollection() {
        index = new HashMap<>();
        list = new ArrayList<>();
        random = new Random();
        n = 0;
    }
    
    public boolean insert(int val) {
        Set set = index.getOrDefault(val, new HashSet<>());
        //存储索引
        set.add(n);
        //存储值
        list.add(val);
        index.put(val, set);
        n++;
        return set.size() == 1;
    }
    
    public boolean remove(int val) {
        if(!index.containsKey(val)){
            return false;
        }
        else{
            //只有移除list中最后一个元素才是O(1)
            int lastIndex = n - 1;
            //找到list中最后一个元素的索引集合
            Set lastset = index.get(list.get(lastIndex));
            //找到要删除元素的索引集合
            Set set = index.get(val);
            //利用迭代器获取要删除元素的一个索引
            int currentIndex = (int)set.iterator().next();
            //交换要删除元素和最后一个元素
            swap(list, currentIndex, lastIndex);
            //删除最后一个元素
            list.remove(lastIndex);
            //删除集合中要删除元素的索引
            set.remove(currentIndex);
            if(set.size() == 0){
                index.remove(val);
            }
            //修改变换位置后最后一个值的索引
            lastset.remove(lastIndex);
            lastset.add(currentIndex);
            n--;
        }
        return true;
    }
    
    public int getRandom() {
        return list.get(random.nextInt(n));
    }
    public void swap(List<Integer> list, int currentIndex, int lastIndex){
        int tmp = list.get(currentIndex);
        list.set(currentIndex, list.get(lastIndex));
        list.set(lastIndex, tmp); 
    }
}

/**
 * Your RandomizedCollection object will be instantiated and called as such:
 * RandomizedCollection obj = new RandomizedCollection();
 * boolean param_1 = obj.insert(val);
 * boolean param_2 = obj.remove(val);
 * int param_3 = obj.getRandom();
 */
  • 17
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值