问题:
Design a data structure that supports all following operations in average O(1) time.
insert(val)
: Inserts an item val to the set if not already present.remove(val)
: Removes an item val from the set if present.getRandom
: Returns a random element from current set of elements. Each element must have the same probability of being returned.
Example:
// Init an empty set. RandomizedSet randomSet = new RandomizedSet(); // Inserts 1 to the set. Returns true as 1 was inserted successfully. randomSet.insert(1); // Returns false as 2 does not exist in the set. randomSet.remove(2); // Inserts 2 to the set, returns true. Set now contains [1,2]. randomSet.insert(2); // getRandom should return either 1 or 2 randomly. randomSet.getRandom(); // Removes 1 from the set, returns true. Set now contains [2]. randomSet.remove(1); // 2 was already in the set, so return false. randomSet.insert(2); // Since 2 is the only number in the set, getRandom always return 2. randomSet.getRandom();
解决:
【解析】设计个数据结构,添加,删除,随机获取都是O(1).
添加和获取耗时O(1)是Array的特性,或者说是Map/Table的特性。
Random要求O(1)那就是需要知道数据结构的大小,并且保证储存的元素是相邻的。
其实就是一个table/map,KEY是添加的元素,value是他储存在array中的位置;
然后一个array和上面的table/map对应;
再一个变量size记录总共有多少个元素,便于random.
① 使用hashmap保存。
class RandomizedSet { //133ms
Map<Integer,Integer> map;
List<Integer> list;//标记对应位置上的值,保证储存的元素是相邻的
int size;//记录数据结构的大小
/** Initialize your data structure here. */
public RandomizedSet() {
map = new HashMap<>();
list = new ArrayList<>();
size = 0;
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
public boolean insert(int val) {
if (map.containsKey(val)){
return false;
}else{
list.add(size,val);
map.put(val,size ++);
return true;
}
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
public boolean remove(int val) {
if(! map.containsKey(val)){
return false;
}
else if (size == 0){
map.remove(val);
return true;
} else {
int removeIndex = map.get(val);
int tailKey = list.get(size - 1);
map.put(tailKey,removeIndex);
list.set(removeIndex,tailKey);
size --;
map.remove(val);
return true;
}
}
/** Get a random element from the set. */
public int getRandom() {
Random random = new Random();
return list.get(random.nextInt(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();
*/
② discuss中的解法。
class RandomizedSet { //133ms
/** Initialize your data structure here. */
//使用数组保存数字
HashMap<Integer,Integer> map;
ArrayList<Integer> list;
java.util.Random rand = new java.util.Random();
public RandomizedSet() {
map = new HashMap<>();
list = new ArrayList<Integer>();
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
public boolean insert(int val) {
if(map.containsKey(val))
return false;
int size = list.size();
map.put(val, size);
list.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(! map.containsKey(val))
return false;
int index = map.get(val);
int size = list.size();
if(index < size - 1){
int temVal = list.get(size - 1);
list.set(index, temVal);
map.put(temVal,index);
}
map.remove(val);
list.remove(size - 1);
return true;
}
/** Get a random element from the set. */
public int getRandom() {
return list.get(rand.nextInt(list.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();
*/