📜  设计一个数据结构,该数据结构支持O(1)中具有重复项的insert,delete,getRandom

📅  最后修改于: 2021-04-17 08:50:17             🧑  作者: Mango

设计一个可以支持O(1)时间复杂度以下操作的数据结构。

  1. insert(x):在数据结构中插入x。如果x不存在,则返回True;如果x已经存在,则返回False。
  2. remove(x):从数据结构中删除x(如果存在)。
  3. getRandom():随机返回流中存在的任何值。返回每个元素的概率应与流中包含的相同值元素的数量成线性比例。

方法:在上一篇文章中,我们已经讨论了用于这种数据结构的方法。但是,以前的数据结构仅适用于唯一值。在本文中,我们将设计一个可以处理重复元素的数据结构。

本文使用的方法与以前的方法非常相似,但是为了处理重复的元素,使用了一组映射来存储动态数组中存在的元素的索引。让我们独立地了解每种方法。

  • insert(int x):
    1. 在动态数组nums []的末尾插入x。
    2. 将x(即nums.size()– 1)的索引插入mp [x] 。该集合映射存储动态数组nums []中存在的元素x的所有索引。
  • 删除(int x):
    1. 通过mp.count(x)检查流中是否存在x。如果不存在,则返回False
    2. 如果存在x,则删除集合mp [x]的第一个元素,并将其值存储在变量indexRemoved中。现在,如果该元素(即indexRemoved)与nums.length()相同,则直接转到步骤6,因为这意味着该元素已经位于最后一个索引,并且该元素会在恒定时间内删除。
    3. 如果不是,则为了在恒定时间内删除此元素,该元素将与动态数组中的最后一个元素交换。因此,从mp [nums [nums.size()– 1]]集中删除值nums.size()– 1。
    4. 将值索引插入mp [nums [nums.size()– 1]]集。
    5. 交换索引为nums.size()– 1和indexRemoved为nums的元素。
    6. 从nums中删除最后一个元素(从Dynamic Array的末尾删除是恒定时间操作)。
    7. 如果mp [val]设置为空,则从mp删除val。
    8. 返回
  • getRandom():
    1. 获取介于0到nums.size()– 1之间的随机数。
    2. 返回此数字索引处存在的值。

下面是上述方法的实现:

// C++ program to design a data structure
// that supports insert, delete,
// getRandom in O(1) with duplicates
  
#include 
  
using namespace std;
  
class Stream {
  
private:
    // Stores all the numbers present
    // currently in the stream
    vector nums;
  
    // Unordered ensure O(1) operation
    unordered_map > mp;
  
public:
    // Function to insert values
    // in the stream
    bool insert(int val)
    {
        // Inserting val to the end of array
        nums.push_back(val);
  
        // Index at which val was inserted
        int index = nums.size() - 1;
  
        // Inserting the index inside the
        // set mp[val]
        mp[val].insert(index);
  
        // Return True if only one val
        // is present in the stream
        return mp[val].size() == 1;
    }
  
    // Function to remove the value
    // from the stream
    bool remove(int val)
    {
  
        // If the value is not present
        // in the stream
        if (!mp.count(val))
            return 0;
  
        // Get the value of the first element
        // of the mp[val] and store it
        // in a variable named index
        int index = *(mp[val].begin());
  
        // Last Index of nums
        int lastIndex = nums.size() - 1;
  
        // Erase the index from mp[val] set
        mp[val].erase(index);
  
        // If index == lastIndex, then the
        // element was already deleted
        // from the stream
        if (index != lastIndex) {
  
            // Delete the lastIndex from
            // mp[nums[lastIndex]] set
            mp[nums[lastIndex]].erase(lastIndex);
  
            // Insert index into mp[nums[lastIndex]] set
            mp[nums[lastIndex]].insert(index);
  
            // Swap the values at index and lastIndex
            swap(nums[index], nums[lastIndex]);
        }
  
        // Delete the last element from nums
        // This operation is O(1) operation
        nums.pop_back();
  
        // If the size of mp[val] is 0,
        // val is absent from the stream
        // and hence it is removed
        if (mp[val].size() == 0)
            mp.erase(val);
        return 1;
    }
  
    // Function to get a random number
    // from the stream of data
    int getRandom()
    {
  
        // Get any random index from 0 to
        // nums.length() - 1
        int randomIndex = rand() % nums.size();
  
// Return the value at that index
        return nums[randomIndex]; 
    }
};
  
// Driver code
int main()
{
  
    Stream myStream;
  
    cout << myStream.insert(5) << endl;
    cout << myStream.insert(6) << endl;
    cout << myStream.insert(5) << endl;
    cout << myStream.remove(6) << endl;
    cout << myStream.remove(6) << endl;
    cout << myStream.getRandom() << endl;
  
    return 0;
}
输出:
1
1
0
1
0
5