“您将如何计算算法的复杂度”这是面试中很常见的问题。您将如何比较两种算法?输入大小很大时,运行时间如何受到影响?因此,这是面试中经常问到的一些问题。在这篇文章中,我们将对算法的复杂性以及大符号进行基本介绍。
什么是算法?
为什么需要评估算法?
计数指令数:
1 2 3 4 5 6 7 8 9 |
整型 n= 数组 .长度 对于 ( 整型 i = 0; i < n; i ++ ) { 如果 ( 数组 [i] == elementToBeSearched) 返回 真正 ; } 返回 假 ; |
让’假设我们的处理器为每个操作取一条指令:
- 用于为变量分配值
- 用于区分两个值
- 乘或加
- 退货声明
在最坏的情况下:
因此:
1 2 3 4 5 |
如果 ( 数组 [i] == elementToBeSearched) ,i ++ 和 i<n <b> 将 是 被执行 n 次 </b> 整型 n= 数组 .长度,i=0,返回 真正 要么 假 <强大> 将 是 被执行 一 时间 . </强大> |
因此f(n)= 3n + 3
渐近行为:
- 随着n变大,我们可以忽略常数3,因为无论n的值如何,常数3始终为3。您可以将3视为初始化常数,并且不同的语言可能需要不同的时间进行初始化,因此其他函数仍为f(n)= 3n。
- 我们可以忽略常数乘数,因为不同的编程语言可能会不同地编译代码。例如,阵列查找可以采用不同语言的不同数量的指令。所以剩下的是f(n)= n
您将如何比较算法?
f(n)=4n^2 +2n+4 和f(n)=4n+4
所以在这里
f(1)= 4 + 2 + 4
f(2)= 16 + 4 + 4
f(3)= 36 + 6 + 4
f(4)= 64 + 8 + 4
….
如您所见,这里的贡献 n^22 随着n值的增加而增加。因此,对于非常大的n值,n的贡献 n^2 将是f(n)值的99%。因此在这里我们可以忽略低阶项,因为它们如上所述相对无关紧要。在此f(n)中,我们可以忽略2n和4.so
n^2+2n+4 ——–>n^2
所以在这里
f(1)= 4 + 4
f(2)= 8 + 4
f(3)= 12 + 4
f(4)= 16 + 4
….
如您所见,这里的贡献 n 随着n值的增加而增加。因此,对于非常大的n值,n的贡献 n 将是f(n)值的99%。因此在这里我们可以忽略低阶项,因为它们相对无关紧要。在这个f(n)中,我们可以忽略4和4作为常数乘数,如上所示,因此
4n+4 ——–>所以这里 n 是最高的增长率。
注意点:
我们放弃所有增长缓慢的术语,而保留增长最快的术语。
大O符号:
因此,O(g(n))是显示算法复杂度的好方法。
让s take some example 和 calculate value 对于 c 和 n0.
1. f(n)= 4n + 3
以f(n)形式书写<= c * g(n),其中f(n)= 4n + 3和g(n)= 5n
4n + 3<对于n0 = 3和c = 5,= 5n。
或4n + 3<=6n 对于 n0=2 和 c=6
以f(n)形式书写<= c * g(n),其中f(n)= 4n + 3和g(n)= 6n
因此对于n0和c可以有多个值,其中f(n)<= c g(n)将得到满足。
2. f(n)=4n^2+2n+4
以f(n)形式书写<=c*g(n) with f(n)=4n^2 +2n+4 和g(n)= 5n ^ 2
4n^2 +2n+4<=5n^2 对于n0 = 4和c = 5
计算算法复杂度的经验法则:
连续声明:
1 2 3 4 |
整型 m=0; //以固定时间c1执行 m=m+1; //以固定时间c2执行 |
f(n)= c1 + c2;
所以O(f(n))= 1
计算一个简单循环的复杂度:
循环的时间复杂度可以通过循环内语句的运行时间乘以迭代总数来确定。
1 2 3 4 5 6 7 |
整型 m=0; //以固定时间c1执行 //执行n次 对于 ( 整型 i = 0; i < n; i ++ ) { m=m+1; //以固定时间c2执行 } |
f(n)= c2 * n + c1;
所以O(n)= n
它是每个循环的迭代结果。
1 2 3 4 5 6 7 8 9 10 11 |
整型 m=0; 被执行 在 不变 时间 c1 //外循环将执行n次 对于 ( 整型 i = 0; i < n; i ++ ) { //内部循环将执行n次 对于 ( 整型 j = 0; j < n; j ++ ) { m=m+1; 被执行 在 不变 时间 c2 } } |
f(n)= c2 * n * n + c1
所以O(f(n))= n^2
当您具有if和else语句时,将使用两者中较大的一个来计算时间复杂度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
整型 甚至计数=0;//以固定时间c1执行 整型 countOfOdd=0; //以固定时间c2执行 整型 k=0; //以恒定时间c3执行 //循环将执行n次 对于 ( 整型 i = 0; i < n; i ++ ) { 如果 (i%2 == 0) //以固定时间c4执行 { 甚至计数 ++ ; //在恒定时间c5执行 k=k+1; //以恒定时间c6执行 } 其他 countOfOdd ++ ; //以恒定时间c7执行 } |
f(n)= c1 + c2 + c3 +(c4 + c5 + c6)* n
所以o(f(n))= n
对数复杂度
让我们借助示例来了解对数复杂度。您可能知道二进制搜索。当您想在排序数组中查找值时,我们使用二进制搜索。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
上市 整型 binarySearch( 整型 [] 已排序 , 整型 第一 , 整型 持续 , 整型 elementToBeSearched) { 整型 迭代=0; 而 ( 第一 < 持续 ) { 迭代 ++ ; 系统 . 出 .打印( “一世” +迭代); 整型 中 = ( 第一 + 持续 ) / 2; //计算中点。 系统 . 出 .打印( 中 ); 如果 (elementToBeSearched < 已排序 [ 中 ]) { 持续 = 中 ; //在上半年重复搜索。 }否则,如果(elementToBeSearched> 已排序 [mid]) { 第一 = 中 + 1; //在最后一半重复搜索。 } 其他 { 返回 中 ; // 找到了。返回位置 } } 返回 -1; //找不到元素 } |
现在让’s假设我们的数组是:
1 2 3 |
整型 [] 已排序 数组 ={12,56,74,96,112,114,123,567}; |
我们想在上面的数组中搜索74。下图将说明二进制搜索将如何在这里工作。
当您仔细观察时,在每次迭代中,您都将数组范围缩小了一半。在每次迭代中,我们都根据soretedArray [mid]覆盖first或last的值。
因此对于
第0次迭代:n
第一次迭代:n / 2
第二次迭代n / 4
第三次迭代n / 8。
概括以上等式:
对于第i次迭代:n /2i
因此,当我们剩下1个元素(即任何i)时,迭代将结束,这将是我们的最后一次迭代:
1=n/2i;
2i = n;
记录后
i = log(n);
因此得出结论,执行二进制搜索所需的迭代次数为log(n),因此 二进制搜索的复杂度为log(n)
就像在我们的示例中一样,我们有n为8。进行了3次迭代(8->4->2->1) 和 3 is log(8).
因此,如果我们在每次迭代中将输入大小除以k,则其复杂度将为O(logk(n)),即log(n)为基础k。
让s take an example:
1 2 3 4 5 6 7 |
整型 m=0; //执行log(n)次 对于 ( 整型 i = 0; i < n; i= 一世* 2) { m=m+1; } |
上面代码的复杂度为O(log(n))。
行使:
让s do some exercise 和 find complexity of given code:
1.
1 2 3 4 5 6 |
整型 m=0; 对于 ( 整型 i = 0; i < n; i ++ ) { m=m+1; } |
答:
1 2 3 4 5 6 7 |
整型 m=0; //执行n次 对于 ( 整型 i = 0; i < n; i ++ ) { m=m+1; } |
复杂度将为O(n)
2.
1 2 3 4 5 6 7 8 9 10 11 |
整型 m=0; 对于 ( 整型 i = 0; i < n; i ++ ) { m=m+1; } 对于 ( 整型 i = 0; i < n; i ++ ) { 对于 ( 整型 j = 0; j < n; j ++ ) m=m+1; } } |
答:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
整型 m=0; //执行n次 对于 ( 整型 i = 0; i < n; i ++ ) { m=m+1; } //外循环执行n次 对于 ( 整型 i = 0; i < n; i ++ ) { //内部循环执行n次 对于 ( 整型 j = 0; j < n; j ++ ) m=m+1; } |
1 2 3 |
} |
复杂度将为:n + n * n—>O(n^2)
3.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
整型 m=0; //外循环执行n次 对于 ( 整型 i = 0; i < n; i ++ ) { //中间循环执行n / 2次 对于 ( 整型 j = n/2; j < n; j ++ ) 对于 ( 整型 k=0; k * k < n; k ++ ) m=m+1; } } } |
答:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
整型 m=0; //外循环执行n次 对于 ( 整型 i = 0; i < n; i ++ ) { //中间循环执行n / 2次 对于 ( 整型 j = n/2; j < n; j ++ ) //内部循环执行log(n)次 对于 ( 整型 k=0; k * k < n; k ++ ) m=m+1; } } } |
复杂度将为n * n / 2 * log(n)–> n^2日志(n)
4.
1 2 3 4 5 6 7 8 9 10 |
整型 m=0; 对于 ( 整型 i = n/2; i < n; i ++ ) { 对于 ( 整型 j = n/2; j < n; j ++ ) 对于 ( 整型 k=0;k < n; k ++ ) m=m+1; } |
答:
1 2 3 4 5 6 7 8 9 10 11 12 |
整型 m=0; //外循环执行n / 2次 对于 ( 整型 i = n/2; i < n; i ++ ) { //中间循环执行n / 2次 对于 ( 整型 j = n/2; j < n; j ++ ) //内部循环执行n次 对于 ( 整型 k=0;k < n; k ++ ) m=m+1; } |
复杂度将为n / 2 * n / 2 * n–> n^3
精湛的解释。在此之前,我经历了许多解释以了解时间复杂性。但是无法理解。非常感谢您的解释。