算法复杂度

2022-08-09  本文已影响0人  bowen_wu

概述

复杂度描述符号

例子

T(n) = 4n2 + 2n + 1

时间复杂度

时间复杂度比较

O(n!) > O(2n) > O(n3) > O(n2) > O(nlogn) > O(n) > O(logn) > O(1)

评判时间复杂度

从数组中查找一个数

时间复杂度计算

一般问题的时间复杂度计算

  1. 基本操作的时间复杂度
    • 丢弃常数项
    • 丢弃次要项
  2. 基本操作执行了多少次 => for/while循环:执行了多少次,时间复杂度就是多少
  3. 复合操作 => 加或乘
例子1
for(int i = 1; i < n; i++) {
   for(int j = i + 1; j <= n; j++) {
      System.out.println(j);
   }
}

T(n) = \sum_{i=1}^{n-1} * \sum_{j=i+1}^n * 1

  1. 计算 \sum_{j=i+1}^n * 1 => 共有多少项 => n - (i + 1) + 1 = n - i
  2. \sum_{i=1}^{n-1} * \sum_{j=i+1}^n * 1 => \sum_{i=1}^{n-1}(n-i) => n-1 + n-2 + n-3 + ... + n-(n-1) => 1到n-1的和
  3. T(n) = (1 + n - 1)(n - 1)/2 = n(n-1)/2
  4. T(n) = O(n2)
例子2
for(int i = 1; i <= n; i = i * 2) {
   for(int j = 1; j <= n; j++) {
      System.out.println(j);
   }
}
  1. 第一个for循环 => 执行了t次 => 2t = n => t = log2n => O(logn)
  2. 第二个for循环 => \sum_{i=1}^{n} => O(n)

T(n) = logn * \sum_{i=1}^{n} * 1 = O(nlogn)

递归问题的时间复杂度计算

求函数表达式

e.g. T(n) = 2T(n/2) + cn

T(n) = 2T(n/2) + cn
     = 2(2T(n/4) + cn/2) + cn
     = 4T(n/4) + 2cn
     = 4(2T(n/8) + cn/4) + 2cn
     = 8T(n/8) + 3cn
        ...
     = nT(n/n) + tcn 
递归树
画递归树步骤

T(n) = aT(n/b) + f(n)

  1. 把根节点T(n)用根为f(n)(代价)、左节点为T(n/2),右节点为T(n/2)的子树代替(以分解、合并子问题需要的代价为根,分解得到的子问题为叶的子树)
  2. 把叶节点按照第一步的方式继续展开。T(n/2)用根为f(n/2)、左节点为T(n/4),右节点为T(n/4)的子树代替
  3. 反复按照第一步的方式迭代,每迭代一次递归树就增加一层,直到树中不再含有权值为函数的节点,即叶子节点为T(1)
主定理
例子1 二分搜索

T(n) = T(n/2) + m

  1. a = 1, b = 2, c = 0
  2. logba = log21 = 0
  3. nc = m => c = 0
  4. T(n) = O(nclogn) = O(logn)
例子2 归并排序

T(n) = 2T(n/2) + O(n)

  1. a = 2, b = 2, c = 1
  2. logba = log22 = 1
  3. T(n) = O(nclogn) = O(nlogn)
经验性结论
例子1
int calculate(int n) {
    if(n <= 0) {
        return 1;
    }
    return calculate(n - 1) + calculate(n - 1);
}


  1. 递归树表达式 => T(n) = T(n-1) + T(n-1) + O(1) = 2T(n-1) + O(1)
  2. 画树
                 1         ---> 1
                / \
               1   1       ---> 2
              / \ / \
             1  1 1  1     ---> 4
             ........
               T(1)
    
  3. T(n) = 1 + 2 + 4 + 8 + ... + n = 等比数列前n项和 => Sn = a1 * (1 - qn) / (1 - q)
  4. T(n) = O(2n)
例子2
int fact(int n) {
    if(n < 0) {
        return -1;
    } else if(n == 0) {
        return 1;
    } else {
        return n * fact(n - 1);
    }
}
  1. 递归树表达式 => T(n) = T(n - 1) + O(1)
例子3
int sum(Node node) {
    if(node == null) {
        return 0;
    }
    return sum(node.left) + node.value + sum(node.right);
}
  1. 设左子树占比 l,右子树占比 r,所以 l + r = 1
  2. T(n) = T(ln) + T(rn) + O(1)
例子4
int fib(int n) {
    if(n <= 0) return 0;
    else if(n == 1) return 1;
    return fib(n - 1) + fib(n - 2);
}
  1. T(n) = T(n - 1) + T(n - 2) + O(1) => O(2n) => 两侧树高度不同,根据数学表达式 => O(1.618n)
void allFib(int n) {
    for(int i = 0; i < n; i++) {
        System.out.println(i + ": " + fib(i));
    }
}

int fib(int n) {
    if(n <= 0) return 0;
    else if(n == 1) return 1;
    return fib(n - 1) + fib(n - 2);
}
  1. T(n) = 1 + 2 + 4 + 8 + ... + 2n - 1 => O(2n)
void allFib(int n) {
    int[] memo = new int[n + 1];
    for(int i = 0; i < n; i++) {
        System.out.println(i + ": " + fib(i, memo));
    }
}

int fib(int n, int[] memo) {
    if(n <= 0) return 0;
    else if(n == 1) return 1;
    else if(memo[n] > 0) return memo[n];
    
    memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
    return memo[n];
}
  1. T(n) = O(n)
例子5
  1. T(n) = nT(n - 1) + O(1) = n(n - 1)T(n - 2) + O(1) = n(n - 1)(n - 2)...2T(1) + O(1) = O(n!)

空间复杂度

上一篇下一篇

猜你喜欢

热点阅读