微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

复杂度与运行时的实际增长不匹配吗?

如何解决复杂度与运行时的实际增长不匹配吗?

我已经做了一段时间的作业表了,我认为无症状复杂性与运行时结果表明之间存在巨大差异。

下面是程序运行时的表。

|      Input Size     |     Runtime (Seconds)   |
|---------------------|-------------------------|
|       10000         |      0.040533803        |
|---------------------|-------------------------|
|       20000         |      0.154712122        |
|---------------------|-------------------------|
|        30000        |      0.330814060        |    
|---------------------|-------------------------|
|        40000        |      0.603440983        |    
|---------------------|-------------------------|
|        50000        |      0.969272780        |    
|---------------------|-------------------------|
|        60000        |      1.448454467        |

Runtime (Seconds) Against Input Size

string = "";
newLetter = "a";
for (int i = 500; i < n; i++) {
    string = string + newLetter;
}
return string

除了我错了,为什么算法的复杂性和运行时间的增长之间会有差异?

从运行时结果看,该程序的时间复杂度为O(n 2 )。输入大小加倍似乎将运行时间增加了4倍,这暗示二次函数

但是从程序本身来看,我可以确定99.9%的时间复杂度实际上是O(n)。

这种差异是否有其他原因?运行时结果确实可能是线性的吗?

对于这种差异,我最好的猜测是for循环会使下一次迭代变慢(这对程序而言是有意义的,因为我认为Java编译器必须迭代给定的每个其他newLetter),但仍然是线性的。 ?它不是嵌套的for循环。

解决方法

您编写的代码实际上确实在时间Θ(n 2 )中运行。原因与这部分代码有关:

string = string + newLetter;

在这里,您的意图是说“请在此字符串的末尾附加一个新字符”。但是,Java实际执行的操作如下:

  1. 计算表达式string + newLetter。这将形成一个全新的字符串,该字符串是通过复制string的全部内容,然后将newLetter附加到该新字符串的末尾而形成的。
  2. 将结果分配给string

这里的问题是,步骤(1)花费的时间越长,字符串的执行时间就越长,因为必须复制所有字符。特别地,如果string的长度为k,则步骤(1)花费时间Θ(k),因为必须复制k个字符。由于string的长度与当前循环迭代索引匹配,因此这意味着完成的工作

Θ(1 + 2 + 3 + ... + n)

=Θ(n(n + 1)/ 2)

=Θ(n 2 ),

这就是为什么您看到自己所看到的情节。

您可以通过使用StringBuilder而不是String来组装较大的字符串来加快速度。它并不会制作所有中间副本,而是维护一个可以根据需要增长的内部数组。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。