【问题标题】:Union-Find leetcode question exceeding time limitUnion-Find leetcode问题超过时限
【发布时间】:2018-09-05 07:12:42
【问题描述】:

我正在 leetcode https://leetcode.com/problems/sentence-similarity-ii/description/ 上解决这个问题,该问题涉及实现 union-find 算法来找出两个句子是否相似或没有给出表示相似单词的对列表。我实现了排名联合查找,我跟踪每个子集的大小并将较小的子树连接到较大的子树,但由于某种原因,代码仍然超过时间限制。有人可以指出我做错了什么吗?如何进一步优化。我看到其他公认的解决方案正在使用相同的排名联合查找算法。

代码如下:

    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;
}

谢谢!

【问题讨论】:

  • 好吧,如果dict 很大,那么按值传递它(到root 函数)可能不是一个好主意。将其作为 const 引用传递可能会有所帮助。
  • 该死的,我简直不敢相信自己。非常感谢。

标签: c++ algorithm graph union-find


【解决方案1】:

就复杂性而言,您的联合发现被打破了。请阅读Wikipedia: Disjoint-set data structure

为了使 union-find 具有接近 O(1) 的复杂性,它必须使用路径压缩。为此,您的 root 方法必须:

  1. 通过引用获取dict,以便对其进行修改。
  2. 对路径上的所有元素进行路径压缩,使它们指向根。

如果不进行压缩,root() 的复杂度将是 O(log N),这可能没问题。但为此,您必须修复它,以便 root() 通过引用而不是通过值获取 dict。按价值传递 dict 成本为 O(N)。

dictstd::map 的事实使得任何查询成本为 O(log N),而不是 O(1)。 std::unordered_map 花费 O(1),但实际上对于 N std::map 更快。此外,即使使用std::unordered_map,散列一个字符串的成本也是 O(len(str))。

如果数据很大,而性能仍然很慢,您可能会从使用pairs 的索引而不是字符串中获得好处,并使用vector&lt;int&gt; 的索引运行union-find。这很容易出错,因为您必须正确处理重复的字符串。

【讨论】:

    猜你喜欢
    • 2018-11-26
    • 1970-01-01
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    • 2022-08-24
    • 1970-01-01
    • 2019-03-03
    • 2011-01-24
    相关资源
    最近更新 更多