在实践和理论上,我们在哪里划定O(1)和O(n)之间的界限?

时间:2019-01-13 01:36:37

标签: time-complexity complexity-theory

假设我们在解决Java问题时遇到了以下问题。

用户输入的密码长度在5个字符到35个字符之间(含5个字符)。我们需要确保它们不会连续重复3次相同的字符。

boolean has3CharsInARow(char [] password){
  for(int left=0, middle=1, right=2; right < password.length; left++, middle++, right++){
    if(password[left]==password[middle] && password[middle]==password[right]){
      return true;
    }
  }
  return false;
}

时间复杂度是多少(为简单起见,假设使用大O符号和最坏的情况)?

我的想法是我们不知道密码中3个字符的位置,因此我们必须搜索所有适当的字符 字符肯定。但是我正在努力将其归类为n个字符的O(1)或O(n)。

O(1)的参数是什么?在上下文的情况下,我们知道它最多只能对密码进行限制 长度为35个字符。因此,在最坏的情况下,我们找不到3个重复的字符,而是扫描O(34)33以找到正确的索引2至34和另外1个 当right为35时,我们退出循环保护,最后返回false。由于34是常数,因此通常说O(34)= O(1),这是恒定的时间复杂度。

O(n)的参数是什么?好吧,我们关心函数的时间效率如何随着输入长度的增加而变化。要是我们 假设T(n)是has3CharsInARow的运行时间,我们可以说T随密码长度的每单位或字符增加而线性增长。因此T在函数O(n)的类别中。

我们在哪里画O(1)和O(n)之间的线?

编辑: 由于一个回答者写了O(n),那么这是否也意味着该等效方法也是O(n)?

boolean has3CharsInARow(char [] password){
  switch(password.length){
    case 0:
    case 1:
    case 2:
        return false;
    case 3: return password[0] == password[1] && password[1] == password[2];
    case 4: return password[0] == password[1] && password[1] == password[2] ||
            password[1] == password[2] && password[2] == password[3];
    ...
    case 35: return ...;

  }
}

1 个答案:

答案 0 :(得分:1)

算法的时间复杂度为O(n)。这里真的没有摆动空间。这是数学和算法分析。为了完整起见,最佳情况是O(1),平均情况下,最坏情况是O(n)

我认为混淆是由于人们不了解大O表示法的含义以及如何解释它。您说(我的意思是):“但是如果我将输入的大小限制为一个常数,那么复杂度实际上就是一个常数,不是吗?”答案是:不会。时间复杂度是对算法的时间执行随着输入的增长如何增长的“描述”。即使输入范围是[5, 35][5, Integer.MAX_VALUE][5, ∞),该“描述”仍然适用。这是运行时与输入大小之间的(相互)关系。

时间复杂度并不能告诉您算法将在什么时间运行。它告诉您更改输入大小对运行时的影响有多大。


让我们看看时间复杂度如何为您提供帮助:

时间复杂度是线性的。对于这么小的输入量,您可以得出一个合理的结论,即该算法是可行的,并且您不必为此担心太多。

但是,如果算法的时间复杂度例如为O(2^n),那么这将告诉您运行时将以很小的输入量爆炸,您将实际上必须查看尺寸35是否仍然可以接受。