您的位置:首页 > 编程语言 > C语言/C++

381. Insert Delete GetRandom O(1) - Duplicates allowed

2017-03-04 19:49 471 查看
Insert Delete GetRandom O1 - Duplicates allowed
题目描述

代码实现

381. Insert Delete GetRandom O(1) - Duplicates allowed

题目描述

Design a data structure that supports all following operations in average O(1) time.

Note: Duplicate elements are allowed.

insert(val): Inserts an item val to the collection.

remove(val): Removes an item val from the collection if present.

getRandom: Returns a random element from current collection of elements. The probability of each element being returned is linearly related to the number of same value the collection contains.

Example:

// Init an empty collection.
RandomizedCollection collection = new RandomizedCollection();

// Inserts 1 to the collection. Returns true as the collection did not contain 1.
collection.insert(1);

// Inserts another 1 to the collection. Returns false as the collection contained 1. Collection now contains [1,1].
collection.insert(1);

// Inserts 2 to the collection, returns true. Collection now contains [1,1,2].
collection.insert(2);

// getRandom should return 1 with the probability 2/3, and returns 2 with the probability 1/3.
collection.getRandom();

// Removes 1 from the collection, returns true. Collection now contains [1,2].
collection.remove(1);

// getRandom should return 1 and 2 both equally likely.
collection.getRandom();


就是弄一个数据结构,使得其可以插入数据、删除数据、返回随机数据。

但是它的时间复杂度只能是O(1)

代码实现

这里我先实现了一种使用map和一个整数记录了其大小。

class RandomizedCollection {
map<int, int> hash;
int size;
public:
RandomizedCollection() {
size = 0;
}

bool insert(int val) {
hash[val]++;
size++;
return (hash[val] == 1);
}

bool remove(int val) {
if(hash.count(val) == 0) return false;
if(--hash[val] == 0) hash.erase(val);
size--;
return true;
}

int getRandom() {
int ind = rand() % size + 1;
map<int, int>::iterator it;
for(it = hash.begin(); it != hash.end(); it++) {
if(ind <= it->second) return it->first;
else ind -= it->second;
}
return it->first;
}
};

/**
* Your RandomizedCollection object will be instantiated and called as such:
* RandomizedCollection obj = new RandomizedCollection();
* bool param_1 = obj.insert(val);
* bool param_2 = obj.remove(val);
* int param_3 = obj.getRandom();
*/


但是这种方法在返回随机数的时候复杂度是O(n),所以这里需要做一些修改。

这里有一种更好的方法,就是使用vector和map进行。使用vector方便搜索,使用map比较容易进行存储索引及值的映射。插入和搜索比较简单,问题是删除会巧妙一点。这里的话,使用的是删除某个元素,那么就把该元素的映射的索引都找到,找到索引最大的那个,把它和vector存储的最外面的元素做一个交换,那么就只需要修改最外面元素的索引,就能把需要的数字删除。

class RandomizedCollection {
map<int, vector<int> > hash;
vector<int> res;
public:
RandomizedCollection() {

}

bool insert(int val) {
hash[val].push_back(res.size());
res.push_back(val);
return (hash[val].size() == 1);
}

bool remove(int val) {
if(!hash.count(val)) return false;
int tp = hash[val].back();
hash[val].pop_back();
if(!hash[val].size()) hash.erase(val);
if(res.size() != tp + 1) {
res[tp] = res[res.size()-1];
hash[res[tp]].pop_back();
hash[res[tp]].insert(hash[res[tp]].begin(), tp);
}
res.pop_back();
return true;
}

int getRandom() {
int sz = res.size();
if(!sz) return 1;
int ind = rand() % sz;
return res[ind];
}
};

/**
* Your RandomizedCollection object will be instantiated and called as such:
* RandomizedCollection obj = new RandomizedCollection();
* bool param_1 = obj.insert(val);
* bool param_2 = obj.remove(val);
* int param_3 = obj.getRandom();
*/


在leetcode1我看到了有人使用multimap,算法效率和上面我写的一样:

class RandomizedCollection {
private:
std::vector<int> nums;
std::unordered_multimap<int, int> pcmap;
public:
/** Initialize your data structure here. */
RandomizedCollection()  {
}

/** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */
bool insert(int val) {
nums.push_back(val);
int count = pcmap.count(val);
pcmap.insert(std::make_pair(val, nums.size() - 1));
return count == 0;
}

/** Removes a value from the collection. Returns true if the collection contained the specified element. */
bool remove(int val) {
auto iter = pcmap.find(val);
if (iter == pcmap.end())
return false;

int pos = iter->second;
pcmap.erase(iter, std::next(iter));

int lastVal = nums.back();
nums[pos] = lastVal;

// Special case in consideration: remove the last inserted value (count: 0->1)
for (auto iterLast = pcmap.find(lastVal); iterLast != pcmap.end(); iterLast++) {
if (iterLast->second == nums.size() - 1) {
pcmap.erase(iterLast, std::next(iterLast));
pcmap.insert(std::make_pair(lastVal, pos));
break; // break early to avoid meaningless loops
}
}

nums.pop_back();  // pop last

return true;
}

/** Get a random element from the collection. */
int getRandom() {
int pos = rand() % nums.size();
return nums[pos];
}
};
/**
* Your RandomizedCollection object will be instantiated and called as such:
* RandomizedCollection obj = new RandomizedCollection();
* bool param_1 = obj.insert(val);
* bool param_2 = obj.remove(val);
* int param_3 = obj.getRandom();
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息