使用getRandom设置

时间:2012-06-16 19:00:04

标签: algorithm data-structures language-agnostic set

这是一个面试问题:Set课程包含getputgetRandom

我会考虑以下选项:

  • 已排序/未排序的链接列表:get - O(N),put - O(N),getRandom - O(N)
  • 未排序的向量(可调整大小的数组):get - O(N),put - ?,getRandom - O(1)
  • 排序向量(可调整大小的数组):get - O(logN),put - ?,getRandom - O(1)
  • 哈希表:get - O(1),put - O(1),getRandom - O(表格大小)
  • 平衡二进制搜索树:get - O(logN),put - O(logN),getRandom - O(N)

看起来最好的候选人是:

  • 哈希表,如果get/putgetRandom
  • 更频繁
  • 如果getRandomget/put更频繁,则排序的矢量(可调整大小的数组)

现在我想知道我们是否可以以某种方式组合向量和散列表来构成更好的集合。

3 个答案:

答案 0 :(得分:5)

您可以将getputgetRandom的平均时间设为O(1)

您所做的是存储2个数据结构。一个是哈希。另一个在可扩展数组中以随机顺序列出元素。

当你put时,你将它放在哈希中,将元素添加到数组的末尾,然后将数组的末尾交换为随机数组元素。

当你get时,你会查看元素的哈希值。

当你getRandom时,你取出数组的最后一个元素,然后将最后一个元素与数组中的另一个点交换。

如果您愿意,可以添加delete,只需删除哈希即可。现在getRandom是通过获取元素来实现的,检查它是否在散列中,如果不是,则缩小数组,然后重复。此时getRandom偶尔O(n) 所有操作的摊销平均成本可以证明为O(1)

答案 1 :(得分:1)

如果你保留一个单独的结构,告诉你哈希表的每个桶中有多少项,你可以使用二进制搜索来找到第n个元素,这将给你所有三个元素的O(log n)操作

一个平衡的二进制搜索树,每个节点增加一个“count”(告诉有多少个节点的子树根植于这个节点)对这些边界也有效。

对上述内容进行了一些更正:您无法在链表中进行随机访问,因此所有操作都是O(N)。另外,两个向量中的put都是O(n),因为必须替换排序版本中的元素并检查未排序版本中的重复项。

答案 2 :(得分:0)

找到~O(1)
删除~O(1)
加~O(1)
对于Random,我们使用包含所有元素的数组,并选择随机元素O(1)

#include <stdio.h>
#include <vector>
#define MOD 666013
using namespace std;

int N;
vector<int> G[MOD];

vector<int>::iterator find(int x)
{
    int list=x%MOD;                  // f(i) = i % MOD this is my hash function
    vector<int>::iterator it;

    for (it=G[list].begin();it!=G[list].end();++it)
        if (*it==x)
            return it;
    return G[list].end();
}

void add(int x)
{
    int list=x%MOD;                     //again this is my hash function that gives me the key
    if (find(x)==G[list].end())
        G[list].push_back(x);
}

void delete(int x)
{
    int list=x%MOD;
    vector<int>::iterator it=find(x);

    if (it!=G[list].end())
        G[list].erase(it);
}