我正在leetcode https://leetcode.com/problems/sentence-similarity-ii/description/上解决此问题,其中涉及实现联合查找算法,以找出两个句子是否相似,或者没有给出代表相似单词的对的列表。我实现了分级联合查找,在其中跟踪每个子集的大小,并将较小的子树连接到较大的子树,但是由于某些原因,代码仍然超出了时间限制。有人可以指出我做错了什么吗?如何进一步优化。我看到其他接受的解决方案正在使用相同排名的联合查找算法。
代码如下:
string root(map<string, string> dict, string element) {
if(dict[element] == element)
return element;
return root(dict, dict[element]);
}
bool areSentencesSimilarTwo(vector<string>& words1, vector<string>& words2, vector<pair<string, string>> pairs) {
if(words1.size() != words2.size()) return false;
std::map<string, string> dict;
std::map<string, int> sizes;
for(auto pair: pairs) {
if(dict.find(pair.first) == dict.end()) {
dict[pair.first] = pair.first;
sizes[pair.first] = 1;
}
if(dict.find(pair.second) == dict.end()) {
dict[pair.second] = pair.second;
sizes[pair.second] = 1;
}
auto firstRoot = root(dict, pair.first);
auto secondRoot = root(dict, pair.second);
if(sizes[firstRoot] < sizes[secondRoot]) {
dict[firstRoot] = secondRoot;
sizes[firstRoot] += sizes[secondRoot];
}
else {
dict[secondRoot] = firstRoot;
sizes[secondRoot] += sizes[firstRoot];
}
}
for(int i = 0; i < words1.size(); i++) {
if(words1[i] == words2[i]) {
continue;
}
else if(root(dict, words1[i]) != root(dict, words2[i])) {
return false;
}
}
return true;
}
谢谢!
答案 0 :(得分:0)
关于复杂性,您的工会发现被打破了。请阅读Wikipedia: Disjoint-set data structure。
要使联合查找具有接近O(1)的复杂度,它必须采用路径压缩。为此,您的root
方法必须:
dict
,以便它可以对其进行修改。不进行压缩,root()
的复杂度为O(log N),可以。但是为此,您必须对其进行修复,以使root()
通过引用而不是通过值获得dict
。按值传递dict
的成本为O(N)。
dict
是std::map
的事实使任何查询成本为O(log N),而不是O(1)。 std::unordered_map
的成本为O(1),但实际上对于N <1000,std::map
的速度更快。另外,即使使用std::unordered_map
,对字符串进行散列也要花费O(len(str))。
如果数据量很大,并且性能仍然很慢,则可以使用索引到pairs
而不是字符串中的索引,然后对索引运行到vector<int>
的联合查找中来。这很容易出错,因为您必须正确处理重复的字符串。