Implement the RandomizedSet class:
RandomizedSet() Initializes the RandomizedSet object.
bool insert(int val) Inserts an item val into the set if not present. Returns true if the item was not present, false otherwise.
bool remove(int val) Removes an item val from the set if present. Returns true if the item was present, false otherwise.
int getRandom() Returns a random element from the current set of elements (it’s guaranteed that at least one element exists when this method is called). Each element must have the same probability of being returned.
You must implement the functions of the class such that each function works in average O(1) time complexity.
Example 1:
Input
[“RandomizedSet”, “insert”, “remove”, “insert”, “getRandom”, “remove”, “insert”, “getRandom”]
[[], [1], [2], [2], [], [1], [2], []]
Output
[null, true, false, true, 2, true, false, 2]
Explanation
RandomizedSet randomizedSet = new RandomizedSet();
randomizedSet.insert(1); // Inserts 1 to the set. Returns true as 1 was inserted successfully.
randomizedSet.remove(2); // Returns false as 2 does not exist in the set.
randomizedSet.insert(2); // Inserts 2 to the set, returns true. Set now contains [1,2].
randomizedSet.getRandom(); // getRandom() should return either 1 or 2 randomly.
randomizedSet.remove(1); // Removes 1 from the set, returns true. Set now contains [2].
randomizedSet.insert(2); // 2 was already in the set, so return false.
randomizedSet.getRandom(); // Since 2 is the only number in the set, getRandom() will always return 2.
Constraints:
- -231 <= val <= 231 - 1
- At most 2 * 105 calls will be made to insert, remove, and getRandom.
- There will be at least one element in the data structure when getRandom is called.
既然是随机抽取,我们自然会想到用一个数组保存所有的数字然后随机生成 index 就可以了。插入部分也不复杂, 我们只需要维护一个 set 来判断当前数字在不在数组中, 不在的话 push 进数组,更新 set 即可。但是到了删除部分就有点复杂了, 本身找到对应的 index 比较简单, 我们只需要将 set 升级为一个 map, 里面保存每次 push 进来的数字的 index 就可以了, 但是数组的删除没法做到 O(1), 所以我们需要用其他办法, 首先想到的肯定是链表, 一个双向链表加一个保存节点指针的 map 应该就可以解决问题, 但是在看过别人的答案之后, 突然发现, 原来还是有更简单的办法的。我们仍然保持一个数组和一个 map 不变, 删除时我们先从 map 里找到 index, 然后把数组里 index 位置的数字换成数组的最后一个数字, 然后我们把数组的最后一个数字删掉并更新 index 位置的那个数字在 map 里的 index, 这样就大功告成了
use rand::prelude::*;
use std::collections::HashMap;
struct RandomizedSet {
nums: Vec<i32>,
locs: HashMap<i32, usize>,
rng: rand::rngs::ThreadRng,
}
/**
* `&self` means the method takes an immutable reference.
* If you need a mutable reference, change it to `&mut self` instead.
*/
impl RandomizedSet {
/** Initialize your data structure here. */
fn new() -> Self {
Self {
nums: Vec::new(),
locs: HashMap::new(),
rng: rand::thread_rng(),
}
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
fn insert(&mut self, val: i32) -> bool {
if self.locs.contains_key(&val) {
return false;
}
self.nums.push(val);
self.locs.insert(val, self.nums.len() - 1);
true
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
fn remove(&mut self, val: i32) -> bool {
if !self.locs.contains_key(&val) {
return false;
}
let &idx = self.locs.get(&val).unwrap();
let last = *self.nums.last().unwrap();
*self.locs.get_mut(&last).unwrap() = idx;
self.nums[idx] = last;
self.locs.remove(&val);
self.nums.pop();
true
}
/** Get a random element from the set. */
fn get_random(&mut self) -> i32 {
let i = self.rng.gen_range(0, self.nums.len() as i32);
self.nums[i as usize]
}
}