【问题标题】:Find all largest sublists from a list where at least two elements are equal从至少两个元素相等的列表中查找所有最大的子列表
【发布时间】:2018-01-16 02:20:51
【问题描述】:

给定一个对象列表和一个非传递相等函数,当两个对象相等时返回 true,否则返回 false,我需要找到至少两个对象相等的所有最大子列表。例如 -

val list = List(o1, o2, o3, o4, o5)

和,

isEqual(o1, o2) => true
isEqual(o2, o4) => true
isEqual(o3, o5) => true

结果将是:

List(o1, o2, o4)
List(o3, o5)

请注意 isEqual 是不可传递的,即在上述情况下,o1 可能不等于 o4,即使它们属于同一个子列表。

【问题讨论】:

  • 如果至少两个对象必须相等,那么列表本身不是最大的子序列,因为它已经包含至少一对相等的对象吗?
  • @Evil Tak - 你是对的。我只是想明确一点。
  • 一个明显的解决方案是首先生成所有可能的相等元组 - 这将花费 O(N^2) 然后找到连接的组件。我想知道这是否可以更快地完成。

标签: algorithm scala graph connected-components set-operations


【解决方案1】:

你的问题等于找到一个图的所有连通分量的问题。

首先要做的是,将您的列表转换为图 G(V, E),其中 V 代表顶点,E 代表边:

V = list
E = {(o1,o2) for all o1,o2 in list| o1.Equals(o2)}

然后创建一个 DFS 来查找所有组件

WHILE-EXISTS unvisted node in G DO
     component[i] = DFS(G)
END

当然是图形本身的组件。 组件是您要查找的列表,组件中的顶点是列表的元素。

对于您的示例,图表如下所示

注意:由于您必须比较每个对象,因此对话将花费 O(n^2)。 要找到所有组件将花费您 O(n)。所以这个算法的渐近运行时间为 O(n^2)

回答您问题中的评论

由于您的问题转换为这个图表问题似乎是正确的, 我很确定这是不可能的。如果您将其视为图形,则只需检查每个节点是否与其他节点相连。你也不能在找到一个相等的节点后停止,因为你可能会找到另一个相等的节点,通过停止,你会分裂连接的组件。

【讨论】:

  • 我刚刚在问题中添加了评论
【解决方案2】:

您可以使用不相交集并集算法来查找所有连接的组件。然后打印列表。以下代码的时间复杂度为 O(NlogN)。 weighted_union 将联合的时间复杂度降低到 logN。因此,如果我在最坏的情况下执行联合 N 次,则需要 NlogN。

#include <bits/stdc++.h>
using namespace std;

int Arr[100], size[100];

int root (int i)
{
    while(Arr[ i ] != i)
    {
        Arr[ i ] = Arr[ Arr[ i ] ] ; 
        i = Arr[ i ]; 
    }
    return i;
}

void weighted_union(int A,int B)
{
    int root_A = root(A);
    int root_B = root(B);
    if(size[root_A] < size[root_B ])
    {
        Arr[ root_A ] = Arr[root_B];
        size[root_B] += size[root_A];
    }
    else
    {
        Arr[ root_B ] = Arr[root_A];
        size[root_A] += size[root_B];
    }
}

void initialize( int N)
{
    for(int i = 0;i<N;i++)
    {
        Arr[ i ] = i ;
        size[ i ] = 1;
    }
}

int main() {
    // your code goes here
    initialize(6);
    weighted_union(1,2);
    weighted_union(2,4);
    weighted_union(3,5);


    map<int, vector<int> >m;
    for (int i=1;i<=5;i++) {
        if(m.find(Arr[i])!=m.end()){
            vector<int> x = m[Arr[i]];
            x.push_back(i);
            m[Arr[i]] = x;
        } else {
            vector<int> x;
            x.push_back(i);
            m[Arr[i]]=x;
        }
    }

    for (std::map<int,vector<int> >::iterator it=m.begin(); it!=m.end(); ++it) {
        vector<int> x = it->second;
        for(int j=0;j<x.size();++j) {
            cout<<x[j]<<" ";
        }
        cout<<endl;
    }

    return 0;
}

您可以在此处找到解决方案的链接:http://ideone.com/vsT9Jh

【讨论】:

  • 感谢您的回复。但是使用这种方法仍然需要 O(N^2) 才能找到所有可能的联合。
  • 不,这会给你所有可能的联合 O(NlogN) + O(different_set * No_of_elements_in_set)
  • 你可以在这里了解更多关于它的时间复杂度:hackerearth.com/practice/notes/disjoint-set-union-union-find
  • 您上面描述的是加权联合查找问题。上面,您假设三个联合(weighted_union(1,2)weighted_union(2,4)weighted_union(3,5))可用。除非我遗漏了什么,在我的情况下,如果我使用联合查找或连接组件方法,我需要首先找到这些元组连接 - 这需要 n^2 时间。
  • 是的,这需要所有关系。你不能优化它,因为它本质上是不可传递的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-11
  • 1970-01-01
  • 2021-08-29
  • 1970-01-01
  • 2020-07-18
  • 1970-01-01
相关资源
最近更新 更多