zoukankan      html  css  js  c++  java
  • 657. Insert Delete GetRandom O(1)

    设计一个数据结构实现在平均 O(1) 的复杂度下执行以下所有的操作。

    • insert(val): 如果这个元素不在set中,则插入。

    • remove(val): 如果这个元素在set中,则从set中移除。

    • getRandom: 随机从set中返回一个元素。每一个元素返回的可能性必须相同。

    样例

    // 初始化空集set
    RandomizedSet randomSet = new RandomizedSet();
    
    // 1插入set中。返回正确因为1被成功插入
    randomSet.insert(1);
    
    // 返回错误因为2不在set中
    randomSet.remove(2);
    
    // 2插入set中,返回正确,set现在有[1,2]。
    randomSet.insert(2);
    
    // getRandom 应该随机的返回1或2。
    randomSet.getRandom();
    
    // 从set中移除1,返回正确。set现在有[2]。
    randomSet.remove(1);
    
    // 2已经在set中,返回错误。
    randomSet.insert(2);
    
    // 因为2是set中唯一的数字,所以getRandom总是返回2。
    randomSet.getRandom();



    其实就是一个数据结构选型的问题
    光用一个vector是不够的,因为每次插入删除都要进行搜索,O(n)
    注意到不能有复数个相同的元素,很容易想到基于红黑树的map,或者比较新的c++11中的unordered_map
    unordered_map和map类似,都是存储的key-value的值,可以通过key快速索引到value。不同的是unordered_map不会根据key的大小进行排序,而map会。

    这两个都能用,甚至在这一题中unordered_map更合适,毕竟key排序在这里无关紧要
    那么现在有一个vector来存储数据,一个map用来当字典索引,接下来怎么做?
    对于插入,先在map里面用count查有没有这个元素,有直接返回,没有就插入vector并在map添加相应tiaomu

    对于删除,还是查map里面有没有这个元素,没有直接返回,有的话:
    1、将vector最后一个值覆盖到要删除值,nums[dict[val]] = nums[nums.size()-1];  这时候vector中有两个最后一个值
    2、将map中最后一个值的位置设成要删除的值的位置,dict[nums[nums.size()-1]]=dict[val]; 这时候map中两个key都指向同一个vector位置
    3、用pop_back()删掉最后一个vector值,用erase删掉map中需要删除的条目

    随机还是很简单的

     1 class RandomizedSet {
     2 private:
     3     vector<int> nums;
     4     map<int, int> dict;
     5 public:
     6     RandomizedSet() {
     7         // do intialization if necessary
     8     }
     9 
    10     /*
    11      * @param val: a value to the set
    12      * @return: true if the set did not already contain the specified element or false
    13      */
    14     bool insert(int val) {
    15         // write your code here
    16         if(dict.count(val)){
    17             return false;
    18         }
    19         nums.push_back(val);
    20         dict[val]=nums.size()-1;
    21     }
    22 
    23     /*
    24      * @param val: a value from the set
    25      * @return: true if the set contained the specified element or false
    26      */
    27     bool remove(int val) {
    28         // write your code here
    29         if(!dict.count(val)){
    30             return false;
    31         }
    32         
    33         nums[dict[val]] = nums[nums.size()-1];  
    34         dict[nums[nums.size()-1]]=dict[val];
    35         
    36         nums.pop_back();  
    37         dict.erase(val);  
    38         return true;  
    39     }
    40 
    41     /*
    42      * @return: Get a random element from the set
    43      */
    44     int getRandom() {
    45         // write your code here
    46         return nums[rand() % nums.size()];
    47     }
    48 };
  • 相关阅读:
    什么样的代码称得上是好代码?
    九年程序人生 总结分享
    Docker入门 第一课 --.Net Core 使用Docker全程记录
    阿里云 Windows Server 2012 r2 部署asp.net mvc网站 平坑之旅
    Visual studio 2015 Community 安装过程中遇到问题的终极解决
    Activiti6.0 spring5 工作流引擎 java SSM流程审批 项目框架
    java 进销存 库存管理 销售报表 商户管理 springmvc SSM crm 项目
    Leetcode名企之路
    24. 两两交换链表中的节点
    21. 合并两个有序链表
  • 原文地址:https://www.cnblogs.com/TheLaughingMan/p/8180901.html
Copyright © 2011-2022 走看看