Union-Find leetcode问题超过时限

Posted

技术标签:

【中文标题】Union-Find leetcode问题超过时限【英文标题】:Union-Find leetcode question exceeding time limit 【发布时间】: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 引用传递可能会有所帮助。 该死的,我简直不敢相信自己。非常感谢。 【参考方案1】:

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

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

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

如果不进行压缩,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。这很容易出错,因为您必须正确处理重复的字符串。

【讨论】:

以上是关于Union-Find leetcode问题超过时限的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode并查集 union-find(共16题)

Union-Find算法详解

解决FastCGI 进程超过了配置的活动超时时限

解决FastCGI 进程超过了配置的活动超时时限

为多个任务设置时限invokeAll

Union-Find