1 时间复杂度估算

1.1 原理

模拟程序的运行次数

1.2 习题演示

  1. public static void test1(int n) {
  2. // O(1)
  3. // 1
  4. if (n > 10) {
  5. System.out.println("n > 10");
  6. } else if (n > 5) { // 2
  7. System.out.println("n > 5");
  8. } else {
  9. System.out.println("n <= 5");
  10. }
  11. // 1 + 4 + 4 + 4
  12. for (int i = 0; i < 4; i++) {
  13. System.out.println("test");
  14. }
  15. }
  16. public static void test2(int n) {
  17. // O(n)
  18. // 1 + 3n(i<n/i++/System...)
  19. for (int i = 0; i < n; i++) {
  20. System.out.println("test");
  21. }
  22. }
  23. public static void test3(int n) {
  24. // 1 + 2n + n * (1 + 3n)
  25. // 1 + 2n + n + 3n^2
  26. // 3n^2 + 3n + 1
  27. // O(n^2)
  28. // O(n)
  29. for (int i = 0; i < n; i++) {
  30. for (int j = 0; j < n; j++) {
  31. System.out.println("test");
  32. }
  33. }
  34. }
  35. public static void test4(int n) {
  36. // 1 + 2n + n * (1 + 45)
  37. // 1 + 2n + 46n
  38. // 48n + 1
  39. // O(n)
  40. for (int i = 0; i < n; i++) {
  41. for (int j = 0; j < 15; j++) {
  42. System.out.println("test");
  43. }
  44. }
  45. }
  46. public static void test5(int n) {
  47. // 8 = 2^3
  48. // 16 = 2^4
  49. // 3 = log2(8)
  50. // 4 = log2(16)
  51. // 执行次数 = log2(n)
  52. // O(logn)
  53. while ((n = n / 2) > 0) {
  54. System.out.println("test");
  55. }
  56. }
  57. public static void test6(int n) {
  58. // log5(n)
  59. // O(logn)
  60. while ((n = n / 5) > 0) {
  61. System.out.println("test");
  62. }
  63. }
  64. public static void test7(int n) {
  65. // 1 + 2*log2(n) + log2(n) * (1 + 3n)
  66. // 1 + 3*log2(n) + 2 * nlog2(n)
  67. // O(nlogn)
  68. for (int i = 1; i < n; i = i * 2) {
  69. // 1 + 3n
  70. for (int j = 0; j < n; j++) {
  71. System.out.println("test");
  72. }
  73. }
  74. }
  75. public static void test10(int n) {
  76. // O(n)
  77. int a = 10;
  78. int b = 20;
  79. int c = a + b;
  80. int[] array = new int[n];
  81. for (int i = 0; i < array.length; i++) {
  82. System.out.println(array[i] + c);
  83. }
  84. }

2 大O表示法

2.1 大O表示法特点

忽略常数、系数、低阶。
对数阶一般省略底数。

2.2 大O表示法示例

  • 9 >> O(1)
  • 2n + 3 >> O(n)
  • n2 + 2n + 6 >> O(n2)
  • 4n3 + 3n2 + 22n + 100 >> O(n3 )
  • log2n = log29 ∗ log9n

    2.3 大O表示法排序

    O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)图片.png

    3 针对斐波那契数列算法的时间复杂度分析

    3.1 代码

    斐波那契数列求和

    3.2 方案一

    代码

    1. public static long basicFibonacci(int num) {
    2. if (num <= 1) {
    3. return num;
    4. }
    5. return basicFibonacci(num - 1) + basicFibonacci(num - 2);
    6. }

    示例图

    图片.png

    讲解

    运行次数上:

  • T(0) = 1

  • T(1) = 1
  • T(N) = T(N-1) + T(N-2) + 1,1指代累加计算

斐波那契数列通过归纳证明法可以证明,当 n >= 1 时 T(n) < (5/3)^n,同时当 n > 4 时 T(n) >= (3/2)^n。
所以该方法的时间复杂度可以表示为 O((5/3)^n),简化后为 O(2^n)。

参考资料

https://zhuanlan.zhihu.com/p/256344121
图片.png

方案二

代码

  1. public static long improvedFibonacci(int num) {
  2. if (num <= 1) {
  3. return num;
  4. }
  5. long first = 0;
  6. long second = 1;
  7. long sum = num;
  8. for (int i = 0; i < num - 1; i ++) {
  9. sum = first + second;
  10. first = second;
  11. second = sum;
  12. }
  13. return sum;
  14. }

讲解

因为记录了子元素的值和对应的和,所以时间复杂度只需要计算for循环。根据大O表示法忽略常数,最终结果是 O(N) 。