问题链接:https://leetcode.com/problems/insert-delete-getrandom-o1/(Medium)和https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/(Hard)
设计一个支持插入、删除和随机取值(所有操作的时间复杂度为O(1))的数据结构。随机取值只能通过均匀分布随机整数生长来实现,那就需要一个整数索引到值的映射O(1)数据结构——ArrayList或者Map。还需要一个O(1)判重数据结构——Set。逻辑结构比较简单直白,代码如下:
class RandomizedSet {
ArrayList<Integer> arrlist;
HashSet<Integer> set;
/** Initialize your data structure here. */
public RandomizedSet() {
arrlist=new ArrayList<>();
set=new HashSet<>();
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
public boolean insert(int val) {
if(set.contains(val))
return false;
else
{
set.add(val);
arrlist.add(val);
}
return true;
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
public boolean remove(int val) {
if(set.contains(val))
{
arrlist.remove(Integer.valueOf(val));
set.remove(val);
return true;
}
return false;
}
/** Get a random element from the set. */
public int getRandom() {
return arrlist.get((int)(Math.random()*set.size()));
}
}
/**
* Your RandomizedSet object will be instantiated and called as such:
* RandomizedSet obj = new RandomizedSet();
* boolean param_1 = obj.insert(val);
* boolean param_2 = obj.remove(val);
* int param_3 = obj.getRandom();
*/
第二问允许重复值的插入,那就维护一个整数值到索引线性表的映射valIndexMap,还有一个索引值到整数值的映射indexValMap。严格来说随机读取操作的时间复杂度不是O(1),但是很奇怪的是Beat 84.1%,仔细想了想,要做到完全的随机读取O(1),就必须使用数组或者ArrayList,但是又要支持O(1)的删除操作,Set和Map可以支持O(1)的删除操作,数组和ArrayList的删除操作必然不可能是O(1),其实数据结构的插入、删除、读取很难同时达到O(1)效率,都是得失并存的。代码如下:
class RandomizedCollection {
HashMap<Integer,LinkedList<Integer>> valIndexMap;
HashMap<Integer,Integer> indexValMap;
int index;
/** Initialize your data structure here. */
public RandomizedCollection() {
valIndexMap=new HashMap<>();
indexValMap=new HashMap<>();
index=0;
}
/** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */
public boolean insert(int val) {
if(valIndexMap.containsKey(val))
{
valIndexMap.get(val).add(index);
indexValMap.put(index++,val);
return false;
}
else
{
LinkedList<Integer> tmp=new LinkedList<>();
tmp.add(index);
valIndexMap.put(val,tmp);
indexValMap.put(index++,val);
return true;
}
}
/** Removes a value from the collection. Returns true if the collection contained the specified element. */
public boolean remove(int val) {
if(valIndexMap.containsKey(val))
{
int tmp=valIndexMap.get(val).pollLast();
indexValMap.remove(tmp);
if(valIndexMap.get(val).size()==0)
valIndexMap.remove(val);
return true;
}
return false;
}
/** Get a random element from the collection. */
public int getRandom() {
int a=(int) (Math.random()*index);
while(!indexValMap.containsKey(a))
a=(int) (Math.random()*index);
return indexValMap.get(a);
}
}
/**
* 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();
*/