Algorithm 检查一对是否包含在白名单中的函数?

Algorithm 检查一对是否包含在白名单中的函数?,algorithm,Algorithm,假设我有一个“白名单对”列表,如下所示: a|b a|c f|g 我想写一个这样的方法: function checkIfInWhitelist(itemOne, itemTwo) { ... } function checkIfInWhitelist(itemOne, itemTwo) { return map.contains(itemOne) && map[itemOne].contains(itemTwo) } 以下是所需的功能: checkIfInW

假设我有一个“白名单对”列表,如下所示:

a|b
a|c
f|g

我想写一个这样的方法:

function checkIfInWhitelist(itemOne, itemTwo) {
    ...
}
function checkIfInWhitelist(itemOne, itemTwo) {
    return map.contains(itemOne) && map[itemOne].contains(itemTwo)
}
以下是所需的功能:

checkIfInWhiteList(a,b)//true

checkIfInWhitelist(b,a)//true

checkIfInWhitelist(b,c)//false

checkIfInWhiteList(g,f)//true

(基本上我想检查白名单中是否存在该对)

做这件事最好最有效的方法是什么

我在想一本字典,其中键是白名单中出现的任何东西,值是与键匹配的东西的列表

例如,上述三对白名单将映射到:

a: [b, c]
b: [a]
f: [g]
g: [f]
然后,
checkIfInWhitelist
将这样实现:

function checkIfInWhitelist(itemOne, itemTwo) {
    ...
}
function checkIfInWhitelist(itemOne, itemTwo) {
    return map.contains(itemOne) && map[itemOne].contains(itemTwo)
}

有没有更好的方法可以做到这一点?

你不可能比O(1)做得更好-只要使用一个哈希实现,它平均为你提供O(1)个查找时间(例如C++STL无序映射)。假设您对内存命中没有问题,这应该是性能最好的解决方案(就执行时间而言,性能最好,不一定是内存开销)。

如果您有一个合理的哈希实现,它可以在
std::pair
(例如Boost中的一个)上工作,并且对象有一个快速的总顺序方法,然后,您可以使用单个哈希表来完成此操作,而无需人为地将表的大小增加一倍。只需使用一个
std::unordered_集
,并在插入前将每一对标准化为非降序。(即,如果a 非常粗糙的代码,缺少很多样板文件。我应该使用完美的转发。没有测试

template<typename T> struct PairHash {
  std::unordered_set<std::pair<T, T>> the_hash_;
  using iterator = typename std::unordered_set<std::pair<T, T>>::iterator;
  std::pair<iterator, bool> insert(const T& a, const T& b) {
    return the_hash_.insert(a < b ? std::make_pair(a, b)
                                  : std::make_pair(b, a));
  }
  bool check(const T& a, const T& b) {
    return the_hash_.end() != the_hash_.find(
             a < b ? std::make_pair(a, b)
                   : std::make_pair(b, a));
  }
};
模板结构PairHash{
std::无序\u设置\u散列\u;
使用iterator=typename std::无序_set::iterator;
标准:成对插入(常数T&a、常数T&b){
返回\u散列\u.insert(a
执行此操作的最小方法:

有一个包含数据和要检查的内容的hashmap

当您想要检查未排序对时,请保留未排序对的哈希映射

使用未排序数据的可能解决方案:

  • 解决方案A保留一组两个
  • 解决方案B将两个值保持在一个特定的顺序,但没有任何意义。例如,(x,y)=>x/y和(y,x)=>x/y。 您只选择上升(或下降):X
解决方案A需要更多的空间和时间(您必须比较集合)

解决方案B需要一个小流程(订单a、B),但其他一切都更快

为了进行检查,您必须预处理:对数据进行无序排序:(a,b)=>a,b(如果a 带有排序数据的解决方案C

预处理的时间较长,但检查的时间(稍微快一点):

在Hashmap中保留each(a,b)和(b,a):例如列表的Hashmap(或Pair的某些实现)

所以你的支票是直接的。但是您的第一个预处理需要:O(2n.log2.n)=2o(n.logn)+2log2o(n)。 因此,这取决于您将在之后处理多少支票

由于比较和反转a和b非常快,我建议使用解决方案b。

如果您知道数据的类型(例如alpha),您可以将这对数据存储在字符串中,如:a-b

您的解决方案不是最优的。

它结合了我的解决方案C和A的不良影响:2嵌入哈希集合和重复数据

它忘记了c:[a]


希望能有所帮助。

“效率”是一个模糊的概念。在几乎所有情况下,您都可以使某些操作更快,而牺牲其他操作的速度。你可以用内存来换取速度。如果目标是尽可能快的存在性检查,那么我会做一个散列或集合[a:b][b:a][a:c][c:a][f:g][g:f],这样每个存在性检查就有一个操作。另一个常数较小的O(1)解呢?那会更好…同意-那确实会更快更好-我是渐进地说:)“渐进地说”对于像这样的小有界问题是没有用的。在许多问题中,可能存在具有更大big-O性能的解决方案,但对于大小有限的问题,这些解决方案的速度更快。例如,对于较小的n,插入排序通常优于O(n logn)排序。恭敬地表示不同意-例如:您使用渐进复杂性给我举了一个例子,其中插入排序优于更优化的比较排序,复杂性为O(nlogn)。为什么这变得重要?因为它的渐近性更好:O(n)相对于nlogn。常数确实重要。我们希望选择快速排序而不是其他比较排序,因为在大多数情况下,其性能中的常量更好。但是,在考虑性能时,渐近复杂性是首选的工具,在这之后,它可以归结为一些特殊情况,在这些情况下,你真正关心的是常数。插入排序是O(n^2),对于较小的n值,它比快速排序的O(n log n)好,因为有常数。渐近线仅适用于大n。Big-O表示法并没有给出具体的性能见解,当然也不适用于小n。由于这是一个大小有界的问题,因此big-O不是适合此工作的工具。