Big O是一个嵌套for循环,其中有Any()吗?

时间:2016-07-12 15:17:01

标签: c# algorithm big-o

这个问题基本上是我answer here的后续问题。我真的想说这个算法的Big-O是什么,但我不确定我的说法是完全合理的。

给定两个数组:

B = [ "Hello World!", "Hello Stack Overflow!", "Foo Bar!", "Food is nice...", "Hej" ]
A = [ "World", "Foo" ]

什么是大O:

List<string> results = new List<string>();
foreach (string test in B)
{
   if (A.Any(a => test.Contains(a))
      results.Add(test);
}

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

5 个答案:

答案 0 :(得分:22)

A的长度为NB的长度为M。我们有两个极端情况:

  1. 最差

    a => test.Contains(a) 
    

    在每个false上返回a,因此A.Any必须扫描整个 A,我们有

    O(N * M) 
    
  2. 最佳一个:

    a => test.Contains(a) 
    

    true的第一项上返回A,因此A.Any 立即返回,我们只有

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

        [O(M)..O(M*N)]
    

答案 1 :(得分:10)

它很接近,但正如其他人提到的那样,O(n*m)因为每个集合的大小不同(最佳情况为O(n),最差情况为O(n*m))否则,如果你两次迭代相同大小的集合,你会得到O(n^2)

Any()

查看幕后故事

您可以查看the source for the Enumerable.Any() method以进一步深入了解这一点。你会看到一个foreach循环来迭代,直到它找到一个匹配谓词,这加强了你对O(n)的假设:

public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
   if (source == null) throw Error.ArgumentNull("source");
   if (predicate == null) throw Error.ArgumentNull("predicate");
   // Another loop to iterate through the collection until the predicate is matched
   foreach (TSource element in source) {
        if (predicate(element)) return true;
   }
   return false;
}

正如您所看到的,Any()本身将是O(n),因为它的长度和嵌套在现有循环O(m)内应该为您提供O(n*m)码。但是,它可能会低至O(m)

答案 2 :(得分:5)

.Any()应该是O(n),因为它会搜索容器,直到找到第一个匹配的实例。因此,在foreach循环中应该是O(n^2)

答案 3 :(得分:5)

我假设您仅提供AB作为其内容的示例,并且您知道复杂性仅对输入集合(如平均,最差和最佳情况)有意义,而不是个人投入。

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

nA.LengthmB.Length。然后可以用几种不同的方式计算给定代码的复杂性:

  1. 假设string.ContainsO(1)。在实践中,可以做出如此强烈的假设,例如,如果我们确切地知道没有字符串比预先确定的长度更长。然后代码复杂性当然是 O(n*m)

  2. 假设string.ContainsO(x*y),其中xy是干草堆和针的长度。设A中最长的字符串长度为k_AB中最长的字符串长度为k_B。然后代码复杂性为 O(n*m*k_A*k_B)

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

    S_AA中所有字符串的长度总和,S_BB中所有字符串的长度总和。然后代码复杂性为 O(S_A * S_B)

    这是最糟糕的情况。但就平均情况而言,对于大多数实际案例,string.ContainsO(x + y)。因此,平均代码复杂度为 O(n*m*(k_A + k_B)) O((S_B + k_A) * n + (S_A + k_B) * m)

答案 4 :(得分:0)

它本质上是一个嵌套的for循环,所以对于最坏的情况,大O应该是O(n ^ 2)