时间复杂度与空间复杂度超详细入门讲解

引入

在学习数据结构与算法之前,我们首先要掌握算法效率 的衡量标准。一个算法的好坏,主要从两个维度去评判:时间效率空间效率

  1. 时间复杂度 :衡量算法运行快慢
  2. 空间复杂度 :衡量算法运行过程中额外占用的内存空间大小

我们写代码不仅要实现功能,更要追求运行更快、占用内存更少。

一、时间复杂度

1.1 概念

时间复杂度用来定量描述:随着数据规模 N 增大,算法中基本语句的执行次数增长趋势。我们不精确计算代码运行的毫秒数,只看执行次数的变化趋势。

1.2 大 O 渐进表示法

算法分析统一使用 大 O 符号 O() 来表示时间复杂度,它描述的是算法执行次数的量级,忽略常数、低次项。

例题:计算 func1 基本操作执行次数
复制代码
void func1(int N){
    int count = 0;
    // 第一层循环:N次
    for (int i = 0; i < N ; i++) {
        // 第二层循环:N次
        for (int j = 0; j < N ; j++) {
            count++;
        }
    }

    // 循环:2*N 次
    for (int k = 0; k < 2 * N ; k++) {
        count++;
    }

    int M = 10;
    // 固定循环10次
    while ((M--) > 0) {
        count++;
    }
    System.out.println(count);
}

总执行次数:N2+2N+10

1.3 大 O 阶推导三步走(必背)

  1. 所有常数全部替换为 1
  2. 只保留式子中最高阶项
  3. 去掉最高阶项前面的系数

补充:算法分析三种情况

  • 最好情况:输入规模下,最小执行次数(下界)
  • 平均情况:期望执行次数
  • 最坏情况 :输入规模下,最大执行次数(笔试面试统一看最坏情况

举例:数组中查找元素 x

  • 最好:1 次找到
  • 最坏:N 次找到
  • 平均:2N 次找到

1.4 常见时间复杂度例题详解

例题 1
复制代码
void func2(int N) {
    int count = 0;
 
    for (int k = 0; k < 2 * N ; k++) {
        count++;
    }
 
    int M = 10;
    while ((M--) > 0) {
        count++;
    }
    System.out.println(count);
}

执行次数:2N+10时间复杂度:O(N)

例题 3
复制代码
void func3(int N, int M) {
    int count = 0;
 
    for (int k = 0; k < M; k++) {
        count++;
    }
 
    for (int k = 0; k < N ; k++) {
        count++;
    }
    System.out.println(count);
}

执行次数:M+N**时间复杂度:O(M+N)**两个未知数都无法忽略。

例题 4
复制代码
void func4(int N) {
    int count = 0;
    // 固定循环100次,和N无关
    for (int k = 0; k < 100; k++) {
        count++;
    }
    System.out.println(count);
}

执行次数固定为 100**时间复杂度:O(1)**只要是固定常数次循环,一律记为 O(1)。

例题 5 冒泡排序 bubbleSort
复制代码
void bubbleSort(int[] array) {
    for (int end = array.length; end > 0; end--) {
        boolean sorted = true;
        for (int i = 1; i < end; i++) {
            if (array[i - 1] > array[i]) {
                Swap(array, i - 1, i);
                sorted = false;
            }
        }
        if (sorted == true) {
            break;
        }
    }
}
  • 最好情况:数组本身有序,执行 N 次
  • 最坏情况:完全逆序,执行 2N(N−1) 次面试只看最坏情况时间复杂度:O(N2)
例题 6 二分查找 binarySearch
复制代码
int binarySearch(int[] array, int value) {
    int begin = 0;
    int end = array.length - 1;
    while (begin <= end) {
        int mid = begin + ((end-begin) / 2);
        if (array[mid] < value)
            begin = mid + 1;
        else if (array[mid] > value)
            end = mid - 1;
        else
            return mid;
    }
    return -1;
}

每查找一次,数据规模砍掉一半。折纸思想:N→2N​→4N​⋯→1执行次数:log2​N时间复杂度:O(logN)

例题 7 递归阶乘 factorial
复制代码
long factorial(int N) {
    return N < 2 ? N : factorial(N-1) * N;
}

递归调用 N 次时间复杂度:O(N)

例题 8 递归斐波那契 fibonacci
复制代码
int fibonacci(int N) {
    return N < 2 ? N : fibonacci(N-1)+fibonacci(N-2);
}

递归展开是一棵二叉树,节点总数约 2N时间复杂度:O(2N)

二、空间复杂度

2.1 概念

空间复杂度衡量:算法运行过程中,额外开辟的临时内存空间大小 。不计算原本传入的数据、形参空间,只统计++额外新开的变量、数组、递归栈帧++。

2.2 常见空间复杂度例题

例题 1 冒泡排序
复制代码
void bubbleSort(int[] array) {
    for (int end = array.length; end > 0; end--) {
        boolean sorted = true;
        for (int i = 1; i < end; i++) {
            if (array[i - 1] > array[i]) {
                Swap(array, i - 1, i);
                sorted = false;
            }
        }
        if (sorted == true) {
            break;
        }
    }
}

只额外开辟了几个固定变量,和 N 无关空间复杂度:O(1)

例题 2 迭代斐波那契数组版
复制代码
int[] fibonacci(int n) {
    long[] fibArray = new long[n + 1];
    fibArray[0] = 0;
    fibArray[1] = 1;
    for (int i = 2; i <= n ; i++) {
        fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
    }
    return fibArray;
}

动态开辟了长度为 n 的数组空间复杂度:O(N)

例题 3 递归阶乘
复制代码
long factorial(int N) {
    return N < 2 ? N : factorial(N-1)*N;
}

递归调用 N 次,产生 N 个栈帧,每个栈帧空间固定空间复杂度:O(N)

三、核心总结

  1. 时间复杂度 看代码执行次数增长趋势,用大 O 表示法
  2. 大 O 推导三原则:常数变 1、只留最高次项、去掉系数;
  3. 算法分析默认看最坏情况
  4. 常见时间复杂度排序:O(1)<O(logN)<O(N)<O(NlogN)<O(N2)<O(2N)
  5. 空间复杂度统计额外开辟的空间:固定变量为 O(1),开数组 / 递归层数为 O(N);
  6. 递归复杂度口诀:
    • 递归调用几次,时间 / 空间就是 O(N)
    • 二分递归时间为 O(logN),二叉树型递归多为指数级。
相关推荐
念越2 小时前
算法每日一题 Day03|快慢双指针解决快乐树问题
算法·力扣
ZPC82102 小时前
MoveGroup 规划轨迹 → 直接交给 MoveIt2 Servo 执行
人工智能·算法·计算机视觉·机器人
️是782 小时前
信息奥赛一本通—编程启蒙(3373:练64.2 图像旋转翻转变换)
数据结构·c++·算法
木子墨5162 小时前
LeetCode 热题 100 精讲 | 计算几何篇:点积叉积 · 线段相交 · 凸包 · 多边形面积
c++·算法·leetcode·职场和发展·动态规划
源码之家2 小时前
计算机毕业设计:Python棉花产业数据可视化与预测系统 Django框架 ARIMA算法 数据分析 可视化 爬虫 大数据 大模型(建议收藏)✅
人工智能·python·算法·信息可视化·数据挖掘·django·课程设计
py有趣2 小时前
力扣热门100题之最小路径和
算法·leetcode
qeen873 小时前
【算法笔记】前缀和经典题目解析
c语言·c++·笔记·学习·算法
Je1lyfish3 小时前
Haskell 初探
开发语言·笔记·算法·rust·lisp·抽象代数
im_AMBER3 小时前
Leetcode 159 无重复字符的最长子串 | 长度最小的子数组
javascript·数据结构·学习·算法·leetcode