如何计算这种奇怪方法的时间复杂度

时间:2012-06-29 00:20:46

标签: c# algorithm

方法是:

List<Book> books = new List<Book>();

public List<Book> Shoot()
{
   foreach(var b in books)
   {
       bool find = true;
       foreach(var otherb in books)
       {
           if(otherb != b && otherb.Author == b.Author)
           {
               find = false;
           }
       }

       if(find)
       {
           yield return b;
       } 
   }
}

通常情况下,时间复杂度为O(books.Count ^ 2),但有一个if(查找) 外循环中的语句可能会改变循环时间。

所以我的问题是:

  1. 这种方法的时间复杂度是多少?
  2. 你是怎么算出来的?
  3. 我正在网上等你的回答。

    提前谢谢。

2 个答案:

答案 0 :(得分:3)

你会遍历外部循环(n)中的每本书,并且对于每个外部书籍,你将在内部循环中经过每个其他b(n次),因此时间复杂度将为O(n ^ 2)。 / p>

yield return不会改变算法的复杂性,它会创建一个迭代器模式,但是如果你从调用函数遍历整个列表,那么你将完成算法中的所有迭代。

What is the yield keyword used for in C#?

为了优化算法,就像提到的那样,你可以对集合进行两次传递,在第一次传递时你将每个作者的书籍数量存储在一个哈希表中,在第二次传递中你检查作者是否有超过一本书使用哈希表(假设查询的时间是恒定的)并且如果出现则产生书:

public List<Book> Shoot()
{
    var authors = new Dictionary<string, int>();
    foreach(var b in books) 
    {
        if(authors.ContainsKey(b.Author))
            authors[b.Author] ++;
        else
            authors.Add(b.Author, 1);
    }

    foreach(var b in books) 
    {
        if(authors[b.Author] == 1)
            yield return b;
    }
}

这样你的线性时间复杂度为O(n),请注意在这种情况下你需要额外的O(n)空间。

答案 1 :(得分:1)

每次收益的最坏情况表现为O(n * n)。你最好的情况是O(n)。如果您假设作者是随机排序的,并且固定部分只编写一本书,那么收益之间的平均情况为O(n),因为到达外部循环的m次迭代的概率呈指数式下降为{ {1}}增加。 (在此处插入标准几何系列参数。)

一般情况下(但并非总是如此!)人们对普通情况最感兴趣。

顺便说一下,处理这个问题的标准方法是预先与所有作者一起创建一个字典,以及他们写的书数量。这需要时间m。然后你的收益只会搜索那个字典的键,只需要一个条目即可查找下一个字典。后续收益率的平均时间为O(n),最差情况为O(1),并且所有收益率的平均摊销时间(假设固定比例仅写入一本书)将为O(n)每让。与当前实现相反,每个产量O(1)