大O方法的复杂性

时间:2010-06-05 11:33:14

标签: performance big-o

我有这个方法:

public static int what(String str, char start, char end)
{
    int count=0;
    for(int i=0;i<str.length(); i++) {
        if(str.charAt(i) == start)
        {
            for(int j=i+1;j<str.length(); j++)
            {
                if(str.charAt(j) == end)
                    count++;
            }
        }
    }
    return count;
}

我需要找到的是:

1)它在做什么?答案:在 EACH 之后计算 end 出现的总数(或者是?在分配中未指定,第3点取决于此) start

2)它的复杂性是什么?答案:第一个循环完全遍历字符串,所以它至少是 O(n),第二个循环只有在找到 start char时执行,甚至是部分(索引)找到 start 的时间+ 1)。虽然,大O都是关于最坏情况的吗?所以在最糟糕的情况下, start 是第一个char&amp;内部迭代遍历字符串n-1次,-1是常量,因此它是 n 。但是,统计上,内部循环不会在每次外部迭代过程中执行,但是由于大O是最坏情况,是否正确,它的复杂性是O(n ^ 2)?忽略任何常量以及内部循环在99.99%的时间内不会执行每个外部循环传递的事实。

3)重写它以降低复杂性 我不确定 start 是否最多出现一次或更多,如果最多一次,那么可以使用一个循环重写方法(有一个标志指示是否遇到了 start ,并且在每次 end 事件时递增 count ,从而产生 O(n)的复杂性

如果 start 可以出现多次,很可能是,因为赋值是Java课程,我认为它们不会这种含糊不清 在这种情况下,使用一个循环无法解决... WAIT !是的,它是..! 只要有一个变量,比如说, inc 每次遇到 start 时都会增加&amp;用于在第一次开始之后每次遇到 end 时递增 count

inc = 0, count = 0
if (current char == start) inc++
if (inc > 0 && current char == end) count += inc

这也会产生 O(n)的复杂性?因为只有一个循环。

是的我意识到我写了很多嘿嘿,但我也意识到,通过将我的想法变成文字,我理解得更好......

3 个答案:

答案 0 :(得分:2)

  1. 在任何给定的开始后,它会为每个结束字符增加`count`。因此,如果有多个开始,它可以在同一端增加多次。
  2. 在最坏的情况下,它会调用charAt(n ^ 2 - n)/ 2 =((n - 1)+(n - 2)+ ... + 1)次。那是O(n ^ 2)。每个角色开始时都会发生这种情况。
  3. 如果你在第一次开始后计算结束字符,你可以简单地在内部后面返回计数。但由于计数递增的次数取决于启动次数,因此最终的伪代码在正确的轨道上。但是,您需要切换ifs的顺序以处理start == end的特殊情况。您也无需检查是否包含&gt; 0。
inc = 0, count = 0

if (current char == end) count += inc
if (current char == start) inc++

在所有情况下都是O(n)。

答案 1 :(得分:1)

1)是的。
2)是的,复杂性最多为O(n),最差为O(n ^ 2) 3)几乎是正确的。您需要检查开始字符前的结束字符,否则结果并不总是正确的。 C#中的示例:

public static int what(string str, char start, char end) {
  int count = 0, mul = 0;
  foreach (char c in str) {
    if (c == end) count += mul;
    if (c == start) mul++;
  }
  return count;
}

答案 2 :(得分:1)

  • 正如马修已经指出的那样,原始方法的复杂性是O( n 2
  • 你的第二种方法不正确,原始方法似乎是计算所有以开始开头并以 end 结尾的子串,也可以包含 开始结束
  • 可以在O( n )中执行此操作,只需查找所有开始,所有结束,然后迭代两个适当移动指针的列表。