我知道这是自行车脱落,但是有一种方法可以在两组(分类的)组A,B的字符串之间获取一组字符串C,其中B是A的子字符串,其复杂度比{ {1}},作为我的幼稚解决方案?
A.size * B.size * comp_substr
使用 std::copy_if(devices.cbegin(), devices.cend(),
std::back_inserter(ports),
[&comport_keys] (const auto& v) {
return std::any_of(comport_keys.begin(),comport_keys.end(), [&v](auto& k) {
return v.find(k) != std::string::npos;
});
});
的B是A的字符串的情况更简单,复杂度为std::set_intersection
,如果必须在{{ 1}},但我不知道如何为它编写比较函数,或者两者都不是。
(A.size + B.size) * comp_substr
答案 0 :(得分:1)
假设我们有两组字符串:A和B。B包含A中字符串的一组潜在前缀。因此,我们希望从A中获取每个元素a并尝试将其与B的所有潜在前缀匹配。 如果找到匹配的前缀,则将结果a存储在C中。平凡的解适用于O(| A | | B |)。您问:我们可以优化它吗?
您说过,B已经排序。然后,我们可以在线性时间内在B上建立广义前缀树,并用A中的每个字符串查询它,以在O(| A | + | B)中进行求解。问题在于,对B进行排序需要O(| B | log | B |),而树是不平凡的。
因此,我提供了一个简单的O(| A | log | B |)解决方案,如果| A |则比O(| A | + | B |)更有效很小,就像您的示例一样。仍然假定B已排序(排序实际上是此处的上限...)。
bool
validate_prefixes(const std::multiset<std::string>& keys) {
auto itb = keys.begin(), it = itb;
if(it == keys.end()) return false; //no keys
for(++it; it != keys.end(); ++it) {
if( (*it).find(*itb) != std::string::npos ) return false; //redundant keys
itb++;
}
return true;
}
bool
copy_from_intersecting_prefixes(const std::vector<std::string>& data,
std::multiset<std::string>& prefix_keys,
std::vector<std::string>& dest, bool check = false) {
if(check && !validate_prefixes(prefix_keys)) return false;
for(auto it_data = data.begin(); it_data != data.end(); ++it_data) {
auto ptr = prefix_keys.insert(*it_data), ptrb = ptr;
if(ptrb != prefix_keys.begin()) { //if data is at the start, there is no prefix
if( (*ptr).find(*(--ptrb)) != std::string::npos ) dest.push_back(*it_data);
}
prefix_keys.erase(ptr);
} //Complexity: O(|data|) * O( log(|prefix_keys|) ) * O(substr) = loop*insert*find
return check;
}
//.... in main()
std::multiset<std::string> tmp(comport_keys.begin(), comport_keys.end()); //copy const
copy_from_intersecting_prefixes(devices, tmp, ports);
validate_prefixes
强制执行一个前提条件。它检查我们是否至少有一个有效的前缀,并且这些密钥不是自匹配的。例如。我们可以有键cu
和cu2
,但是cu
是cu2
的前缀,因此它们不能都是有效的前缀,cu
也是一般或cu2
太具体。如果我们尝试将cu3
与cu
和cu2
进行匹配,则这是不一致的。这里validate_prefixes(comport_keys)
返回true
,但最好自动检查一下。
copy_from_intersecting_prefixes
完成实际要求的工作。它在A上进行迭代,并将a放入有序B内。前缀小于prefix + ending,因此,如果存在对应的前缀,它将出现在B中的a之前。由于键不是自匹配的,因此我们知道前缀将在B中位于a之前。因此我们将迭代器从a中减去并进行比较。请注意,前缀可能等于a,因此我们需要多集。