时间复杂度

概念

指输入数据大小为N时,算法运行所需要的时间。
注意:

  • 统计的是算法的【计算操作数量】,而不是【运行的绝对时间】;计算操作数量和运行绝对时间呈正相关关系,并不相等。算法运行时间受到(编程语言、计算机处理器速度、运行环境)等多种因素影响。
  • 体现的是计算操作随数据N变化时的变化情况。
  • 假设算法运行时总共需要1次操作、100次操作,此两种情况的时间复杂度都为常数级O(1);需要N次操作、100N次操作的时间复杂度都为O(N)

    符号表示

  • 最差 —— O

  • 平均 —— Θ
  • 最佳 —— Ω

示例:

  1. boolean findSeven(int[] nums){
  2. for (int num : nums){
  3. if (num == 7){
  4. return true;
  5. }
  6. }
  7. return false;
  8. }
  • 最佳情况Ω(1):nums[7,a,s,d,f…],即当数组首个数字为7时,无论nums有多少元素,循环次数都为1。
  • 最差情况O(N):nums[a,s,c,f,f…]且nums中所有数字都不为7时,此时会遍历整个数组,循环N次。
  • 平均情况Θ:需要考虑输入数据的分布情况,计算所有数据情况下的平均时间复杂度。
    • 本题目需要考虑数组长度、数组元素的取值范围等。

注意:
O是最常用的时间复杂度评价渐进符号。

常见种类

从小到大:
O(1) < O(logN) < O(N) < O(N log N) < O(N2) < O(2N) < O(N!)
1623519242-UTNefQ-Picture1.png

示例解析

常数O(1)

运行次数与N大小呈常数关系,即不随输入数据大小N的变化而变化。

  1. int algorithm(int N) {
  2. int a = 1;
  3. int b = 2;
  4. int x = a * b + N;
  5. return 1;
  6. }
  7. int algorithm(int N) {
  8. int count = 0;
  9. int a = 10000;
  10. for (int i = 0; i < a; i++) {
  11. count++;
  12. }
  13. return count;
  14. }

1623779241-lViysV-Picture2.png

线型O(N)

循环运行次数与N大小呈线型关系,时间复杂度为O(N)
示例:

  1. int algorithm(int N){
  2. int count = 0;
  3. for (int i = 0; i < N; i++){
  4. count++;
  5. }
  6. return count;
  7. }
  8. //以下代码虽然是两层循环,但是第二层与N的大小无关,因此整体仍与N呈线型关系
  9. int algorithm(int N){
  10. int count = 0;
  11. int a = 10000;
  12. for (int i = 0; i < N; i++){
  13. for (int j = 0; j < a; j++){
  14. count++;
  15. }
  16. }
  17. return count;
  18. }

2b1af1eb-6fee-4558-bd61-1d87efb997aa.png

平方O(N2)

两层循环相互独立,都与N呈线型关系,因此总体与N呈平方关系,时间复杂度为O(N2)。
示例:

  1. int algorithm(int N){
  2. int count = 0;
  3. for (int i = 0; i < N; i++){
  4. for (int j = 0; j < N; j++){
  5. count++;
  6. }
  7. }
  8. return count;
  9. }

以【冒泡排序】为例,其包含两层独立循环:

  1. 第一次复杂度为O(N)
  2. 第二层平均循环次数为N/2,复杂度为O(N)
  3. 推导过程如下:
    1. O(N/2) = O(1/2)O(N) = O(1)O(N) = O(N)

因此,冒泡排序的总体时间复杂度为O(N2),代码示例:

  1. int[] bubbleSort(int[] nums){
  2. int N = nums.length;
  3. for (int i = 0; i < N-1; i++){
  4. for (int j = 0; j < N-1-i; j++){
  5. if (nums[j] > nums[j+1]){
  6. int tmp = nums[j];
  7. nums[j] = nums[j+1];
  8. num[j+1] = tmp;
  9. }
  10. }
  11. }
  12. return nums;
  13. }

1623519242-piiPrs-Picture4.png

指数O(2N)

生物学科中的“细胞分裂”即是指数级增长。初始状态为1个细胞,分裂一轮后为2个,分裂两轮后为4个,……,分裂N轮后有2N个细胞。
代码示例:

  1. int algorithm(int N){
  2. if (N <= 0){
  3. return 1;
  4. }
  5. int count_1 = algorithm(N-1);
  6. int count_2 = algorithm(N-1);
  7. return count_1 + count_2;
  8. }

1623519242-XLBkIT-Picture5.png

阶乘O(N!)

阶乘阶对应数学上常见的“全排列”。即给定N个互不重复的元素,求其所有可能的排列方案:
N (N - 1) (N - 2) …… 2 * 1 = N!
阶乘通常使用递归实现,算法原理:
第一层分裂出N个,第二层分裂出N-1个,……直到第N层终止并回溯;

  1. int algorithm(int N) {
  2. if (N <= 0) {
  3. return 1;
  4. }
  5. int count = 0;
  6. for (int i = 0; i < N; i++) {
  7. count += algorithm(N - 1);
  8. }
  9. return count;
  10. }

1623519242-AFSqrK-Picture6.png

对数O(log N)

对数阶与指数阶相反,指数阶为“每轮分裂出两倍的情况”,而对数阶是“每轮排除一半的情况”。
对数阶常出现于【二分法】、【分治】算法,体现着:一分为二和一分为多的算法思想。
示例:
设置循环次数为m,则输入数据大小N与2m呈线型关系,两边同时取log2对数,则得到循环次数m与log2N呈线性关系,即时间复杂度为O(logN)

  1. int algorithm(int N){
  2. int count = 0;
  3. folat = N;
  4. while (i > 1){
  5. i = i / 2;
  6. count ++;
  7. }
  8. return count;
  9. }

1623519242-WthaZa-Picture7.png

线性对数O(N log N)

概念:
两层循环相互独立,第一层和第二层时间复杂度分别为O(log N)和O(N),则总体时间复杂度为O(N log N)。

  1. int algorithm(int N) {
  2. int count = 0;
  3. float i = N;
  4. while (i > 1){
  5. i = i / 2;
  6. for (int j = 0; j < N; j++){
  7. count ++;
  8. }
  9. }
  10. return count;
  11. }

线型对数阶常出现于排序算法,例:快速排序、归并排序、堆排序等。
时间复杂度原理图:
1623519242-rhCOIh-Picture8.png

示例题目

时间复杂度 示例题解
O(1) https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/5vyva2/
https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/572x9r/
O(log N) https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/57p2pv/
https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/58lgr7/
O(N) https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/9p7s17/
https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/50fji7/
O(N log N) https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/59ceyt/
https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/o53yjd/
O(N2) https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/5vwbf6/
https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/5dz9di/
O(N!) https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/50hah3/

空间复杂度