提问人:M.A 提问时间:11/14/2023 最后编辑:M.A 更新时间:11/16/2023 访问量:100
while 循环执行 sum(n-1) 时间的大 O
the big O of while loop executed sum(n-1) time
问:
如果有人可以帮助我:
1- 这段代码的时间复杂度(Big O)是多少?
2- 如果这段代码的大 O = O(n^2),那么哪个更好使用(虽然像这段代码一样)或(两个嵌套的 for 循环)?
代码:
l = [1, 2, 3, 4, 6, 5] // big O => O(1)
ll = list(l) // big O => O(1)
a = 0 // big O => O(1)
b = 1 // big O => O(1)
x = 0 // big O => O(1)
y = 0 // big O => O(1)
while a < len(l)-1: // big O => O(?)
x = l[a] // big O => O(1)
y = l[b] // big O => O(1)
if x > y : // big O => O(1)
ll[a] = 0 // big O => O(1)
a += 1 // big O => O(1)
b =a+1 // big O => O(1)
elif b >= len(l)-1: //big O => O(1)
a += 1 // big O => O(1)
b = a + 1 // big O => O(1)
continue // big O => O(?)
else : // big O => O(1)
b += 1 // big O => O(1)
continue // big O => O(?)
print(ll) // big O => O(1)
在上述代码的最坏情况下,make while 循环执行了 (n-1)
时间的总和,例如:
if n = 1 then while loop will execute 0 time
if n = 2 then while loop will execute 1 time
if n = 3 then while loop will execute 3 time
if n = 4 then while loop will execute 6 time
if n = 6 then while loop will execute 15 time
.
.
.
if n = k then while loop will execute sum(k-1) time
我希望我的问题很清楚。
答:
代码的时间复杂度为 O(n²)。
关于您的分析的一些评论:
ll = list(l) // big O => O(1)
该函数(在 Python 中)创建一个新列表,因此这实际上是 O(n)list
continue // big O => O(?)
该语句需要恒定的时间才能执行,因此 O(1)。但是,在使用 的地方,您可以简单地删除这些语句,因为它们不起作用(它们已经是在循环的当前迭代中执行的最后一个语句)。continue
continue
print(ll) // big O => O(1)
打印列表所需的时间与列表的长度一样长(需要输出每个字符),因此这是 O(n)。另一方面,打印不应该成为复杂性分析的一部分。你最好把你的算法写成一个函数,它只返回结果。由调用者决定是否应该打印该列表,无论如何,这不是算法的一部分,也不应该进行分析。
主要问题是循环进行迭代的次数。如果我们丢弃以 开头的块,则 并获取可以从 {0,..,n−1} 获取的所有可能对的值,其中 .例如,如果 n 为 4,则 和 的值演变如下:if
if x > y
a
b
a < b
a
b
迭 代 | 一个 | b |
---|---|---|
1 | 0 | 1 |
2 | 0 | 2 |
3 | 0 | 3 |
4 | 1 | 2 |
5 | 1 | 3 |
6 | 2 | 3 |
因此,有 3 次迭代,其中 0,2 次迭代,其中 1 次,以及 1 次迭代,其中 2。这样总共有 1+2+3+...+n−1 次迭代,这是一个三角形数,可以表示为 n(n−1)/2,即 O(n²)。a
a
a
O(n²) 是最坏情况的复杂度,因为块可能导致增加的速度比上面解释的要快。在最好的情况下,你的输入将是一个递减序列([5, 4, 3, 2, 1]),然后这个块将在外循环的每次迭代中执行,所以你只得到外循环的n-1次迭代,这使得它成为O(n)。if x > y
a
if
代码改进
在 Python 中,最好不要在循环变量上使用显式语句,而是使用迭代器或范围进行循环。例如,以下代码实现了相同的逻辑:a += 1
def solve(l):
return [
0 if any(l[b] < x for b in range(a + 1, len(l))) else x
for a, x in enumerate(l)
]
这里是用来找出是否有任何(之后)的。如果是这样,则应将值替换为 0,否则,我们保留原始值。此列表推导会创建一个新列表,因此它将调用与循环中的逻辑相结合。any
b
a
l[b] < l[a]
a
x
list(l)
降低时间复杂度
我们还可以使用更有效的不同算法。如果我们向后遍历列表,那么我们可以跟踪到目前为止遇到的最小值。每当我们遇到大于该最小值的值时,我们都会将其替换为 0。这样我们就没有内部循环了,过程变成了 O(n):
def solve(l):
low = l[-1] # keep track of the least value found so far
result = [
0 if (low := min(y, low)) < y else y
for y in reversed(l)
]
result.reverse()
return result
评论
1+2+...+(n-1)
O(n^2)
O(1)
O(n^2)
i=count - 1