C# 嵌套for循环的大O是什么,其中包含Any()?

C# 嵌套for循环的大O是什么,其中包含Any()?,c#,algorithm,big-o,C#,Algorithm,Big O,这些问题基本上是我的后续问题。我真的想说这个算法的大O是什么,但我不确定我的说法是否完全正确 因此,给定两个数组: B = [ "Hello World!", "Hello Stack Overflow!", "Foo Bar!", "Food is nice...", "Hej" ] A = [ "World", "Foo" ] 最大的问题是什么: List<string> results = new List<string>(); foreach (string t

这些问题基本上是我的后续问题。我真的想说这个算法的大O是什么,但我不确定我的说法是否完全正确

因此,给定两个数组:

B = [ "Hello World!", "Hello Stack Overflow!", "Foo Bar!", "Food is nice...", "Hej" ]
A = [ "World", "Foo" ]
最大的问题是什么:

List<string> results = new List<string>();
foreach (string test in B)
{
   if (A.Any(a => test.Contains(a))
      results.Add(test);
}
列表结果=新列表();
foreach(B中的字符串测试)
{
如果(A.Any(A=>test.Contains(A))
结果。添加(测试);
}

我认为它介于
O(n)
O(n^2)
之间,因为它取决于
Any()
在结果中匹配的位置…

很接近,但是正如其他人提到的,它将是
O(n*m)
,因为每个集合的大小不同(最好的情况是
O(n)
,最坏的情况是
O)(n*m)
)否则,如果重复两次相同大小的集合,则会得到
O(n^2)

Any()

您可以看一看,进一步深入了解这一点。您将看到一个
foreach
循环,以进行迭代,直到找到谓词的匹配项,这加强了您对它是
O(n)
的假设:

public static bool Any(此IEnumerable源代码,Func谓词){
if(source==null)抛出错误.ArgumentNull(“source”);
if(predicate==null)抛出Error.ArgumentNull(“predicate”);
//另一个循环遍历集合,直到谓词匹配为止
foreach(源中的TSource元素){
if(谓词(元素))返回true;
}
返回false;
}

正如你所见,
Any()
本身就是
O(n)
,因为它的长度和嵌套在一个现有的循环中
O(m)
应该给你整个代码
O(n*m)
。然而,它可能会低到
O(m)

A
的长度为
N
B
的长度为
M
。我们有两种极端情况:

  • 最糟糕的是:

    在每个
    a
    上返回
    false
    ,因此
    a。任何
    都必须扫描整个
    a
    ,我们必须

    O(N * M) 
    
  • 最好的:

    A
    的第一项返回
    true
    ,因此
    A。任何
    立即返回,我们只有

    O(M)
    
  • 实际复杂性介于两者之间(包括两个边界):


    .Any()
    应该是
    O(n)
    ,因为它搜索容器直到找到第一个匹配的实例。因此,在foreach循环中应该是
    O(n^2)
    它本质上是一个嵌套的for循环,所以大O应该是O(n^2)对于最坏的情况

    我假设您只提供了
    A
    B
    作为其内容的示例,并且您知道复杂性仅对输入集(如平均、最坏和最佳情况)有意义,而不是对单个输入有意义

    我的观点是,根据问题需求和用例,您可以对代码复杂性做出非常不同的估计

    n
    be
    A.Length
    m
    be
    B.Length
    。然后可以用几种不同的方法计算给定代码的复杂性:

  • 假设
    string.Contains
    O(1)
    。在实践中,可以做出这样的假设,例如,如果我们确信没有字符串长度超过某个预先确定的长度。那么代码复杂性当然是
    O(n*m)

  • 假设
    string.Contains
    O(x*y)
    ,其中
    x
    y
    是草堆和针的长度。让
    A
    中最长的字符串的长度
    k\u A
    B
    中最长的字符串的长度
    k\u B
    那么代码的复杂度将是
    O(n*m*k\u A*k\B)

  • 对于第二种情况,还有另一种(更实际的)方法:

    假设
    S_A
    A
    中所有字符串的长度之和,
    S_B
    B
    中所有字符串的长度之和。那么代码复杂度将是
    O(S_A*S_B)


    最坏的情况就是这样。不过,对于一般情况和最实际的情况,
    string.Contains
    O(x+y)
    。因此平均代码复杂度将是
    O(n*m*(k_A+k_B))
    O((s_B+k_A)*n+(s_A+k_B)*m)

    我很确定它仍然被认为是一个O(n^2)算法,即使它可以提前中断。@heijp06这两个算法都是,因为算法对这两个都进行了迭代。因此O(n^2)@heijp06 Big-O表示法不考虑单个数据集。它是对算法的高级别效率评估。没有优化的嵌套迭代(例如二进制搜索)是O(n^2)。由于输入是常量,因此算法也是常量complexity@itsme86这里的复杂性是
    O(mn)
    m
    B的长度
    n
    A的长度
    A
    只有
    O(n^2)
    如果
    m=cn
    足够大
    n
    ,并且
    c
    一些常数独立于
    m
    n
    ,那么我们就有了
    m=cn
    O(mn)=O(cn^O>(n^2)
    。但问题陈述中没有任何东西表明可以进行简化。需要明确的是:最佳情况复杂度为O(M),最坏情况复杂度为O(MN),平均情况复杂度为O(M*(n/2))=O(MN)@Robin:在处理平均情况时,我们必须知道分布情况(即什么的平均值);这个问题没有提供任何暗示。你已经解决了这样一个问题:当
    A
    的每一项都在
    B
    的某个地方(
    B
    的所有项都是不同的),并且
    A
    项在
    B
    中的分布是统一的,这是很公平的。
    包含的运行时对于这个任务来说并不是微不足道的
    
    O(N * M) 
    
    a => test.Contains(a) 
    
    O(M)
    
        [O(M)..O(M*N)]