跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

动态规划时间复杂度和空间复杂度计算方法

综述由AI生成讲解动态规划(DP)时间与空间复杂度的计算方法。核心公式为时间复杂度等于状态数量乘以单个状态计算成本。通过一维和二维 DP 示例(如斐波那契数列、最小路径和、背包问题),展示了如何确定状态数和计算成本。空间复杂度取决于存储的状态数,可通过滚动数组等技巧优化。文章总结了常见 DP 问题的复杂度对比及避坑指南,帮助开发者准确评估算法性能。

筑梦师发布于 2026/3/30更新于 2026/5/2527 浏览

一、先明确核心概念(新手易懂版)

  • 状态:就是 DP 里定义的 dp[i]、dp[i][j] 这类表示子问题的变量,比如 dp[i] 是第 i 个斐波那契数,dp[i][j] 是前 i 个物品装容量 j 背包的最大价值。
  • 状态数量:所有需要计算的子问题数量(比如一维 DP 的状态数是 n,二维 DP 是 n*m)。
  • 单个状态计算成本:算一个状态(比如 dp[i])需要的操作数(通常是 O(1),少数是 O(k))。

二、时间复杂度计算(核心公式)

公式:

时间复杂度 = 状态数量 × 单个状态的计算成本

分场景拆解(结合 C++ 例子)
场景 1:一维 DP(如斐波那契数列)
// 一维 DP:dp[i] = dp[i-1] + dp[i-2]
int fib_dp(int n) {
    if (n <= 2) return 1;
    vector<int> dp(n+1);
    dp[1] = 1;
    dp[2] = 1;
    for (int i=3; i<=n; i++) {
        dp[i] = dp[i-1] + dp[i-2]; // 单个状态计算成本:O(1)
    }
    return dp[n];
}
  • 状态数量:需要计算 dp[3] 到 dp[n],共 n-2 个状态,约等于 O(n)。
  • 单个状态计算成本:算 dp[i] 只需要做一次加法,是 O(1)。
  • 时间复杂度:O(n) × O(1) = O(n)。
场景 2:二维 DP(如最小路径和)
// 二维 DP:dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
int minPathSum(vector<vector<int>>& grid) {
    int m = grid.size(), n = grid[0].size();
    vector<vector<int>> dp(m, vector<int>(n));
    dp[0][0] = grid[0][0];
    // 初始化第一行
    for (int j=1; j<n; j++) dp[0][j] = dp[0][j-1] + grid[0][j];
    // 初始化第一列
    for (int i=1; i<m; i++) dp[i][0] = dp[i-1][0] + grid[i][0];
    // 计算其他状态
    for (int i=1; i<m; i++) {
        for (int j=1; j<n; j++) {
            dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]; // O(1)
        }
    }
    return dp[m-1][n-1];
}
  • 状态数量:二维数组 dp[m][n],共 m×n 个状态,即 O(m*n)。
  • 单个状态计算成本:算 dp[i][j] 只需要一次 min 和一次加法,是 O(1)。
  • 时间复杂度:O(m*n) × O(1) = O(mn)。
场景 3:单个状态计算成本非 O(1)(如完全背包)
// 完全背包:dp[j] = max(dp[j], dp[j-weight[i]] + value[i])
int completeKnapsack(vector<int>& weight, vector<int>& value, int bagSize) {
    vector<int> dp(bagSize+1, 0);
    for (int i=0; i<weight.size(); i++) { // 遍历物品
        for (int j=weight[i]; j<=bagSize; j++) { // 遍历背包容量
            dp[j] = max(dp[j], dp[j-weight[i]] + value[i]); // 单个状态计算
        }
    }
    return dp[bagSize];
}
  • 状态数量:背包容量是 bagSize,状态数是 O(bagSize)。
  • 单个状态计算成本:每个状态需要遍历所有物品(数量为 n),是 O(n)。
  • 时间复杂度:O(bagSize) × O(n) = O(n×bagSize)。

三、空间复杂度计算(核心:看存储的状态数)

核心逻辑:

空间复杂度 = 存储 DP 状态所用的额外空间(不包含输入空间),分'原始版'和'优化版'两种情况。

分场景拆解
场景 1:一维 DP 原始版(斐波那契)
vector<int> dp(n+1); // 存储 n+1 个状态
  • 空间复杂度:O(n)(存储了 n+1 个 int,约等于 O(n))。
场景 2:一维 DP 空间优化版(斐波那契)
// 只用两个变量存前两个状态,不用数组
int prev_prev = 1, prev = 1, curr;
  • 存储的状态数:固定 2 个变量,和 n 无关。
  • 空间复杂度:O(1)(常数空间)。
场景 3:二维 DP 原始版(最小路径和)
vector<vector<int>> dp(m, vector<int>(n)); // 存储 m×n 个状态
  • 空间复杂度:O(mn)。
场景 4:二维 DP 空间优化版(最小路径和)
// 只用一维数组,覆盖更新
vector<int> dp(n, 0);
dp[0] = grid[0][0];
for (int j=1; j<n; j++) dp[j] = dp[j-1] + grid[0][j];
for (int i=1; i<m; i++) {
    dp[0] += grid[i][0]; // 第一列更新
    for (int j=1; j<n; j++) {
        dp[j] = min(dp[j], dp[j-1]) + grid[i][j]; // 覆盖旧值
    }
}
  • 存储的状态数:只有一维数组 dp[n],状态数是 O(n)(也可优化到 O(min(m,n)))。
  • 空间复杂度:O(n)。

四、新手避坑点

  1. 混淆'状态数量'和'循环次数':循环次数本质就是状态数量,比如二维 DP 的两层循环,次数就是 m×n,对应状态数 m×n。
  2. 忽略空间优化的影响:原始 DP 的空间复杂度等于状态数,但优化后可能降维(二维→一维→常数),时间复杂度不变(因为还是要算所有状态)。
  3. 把输入空间算进去:复杂度只算'额外空间',比如输入的 grid[m][n] 不算,只算自己定义的 dp 数组。

五、典型 DP 问题复杂度总结(快速参考)

问题状态定义时间复杂度原始空间复杂度优化后空间复杂度
斐波那契数列dp[i]O(n)O(n)O(1)
最小路径和dp[i][j]O(mn)O(mn)O(n)
01 背包dp[i][j]O(n×bagSize)O(n×bagSize)O(bagSize)
最长递增子序列dp[i]O(n²)O(n)O(n)(无法优化到 O(1))

总结
  1. 时间复杂度:核心是「状态数量 × 单个状态计算成本」,大部分场景单个状态成本是 O(1),复杂度就是状态数。
  2. 空间复杂度:原始版等于存储的状态数(一维 O(n)、二维 O(mn)),优化版通过'复用空间'降维(比如二维→一维、一维→常数)。
  3. 优化空间不会改变时间复杂度,因为还是要计算所有状态,只是少存了中间结果。

目录

  1. 一、先明确核心概念(新手易懂版)
  2. 二、时间复杂度计算(核心公式)
  3. 公式:
  4. 分场景拆解(结合 C++ 例子)
  5. 场景 1:一维 DP(如斐波那契数列)
  6. 场景 2:二维 DP(如最小路径和)
  7. 场景 3:单个状态计算成本非 O(1)(如完全背包)
  8. 三、空间复杂度计算(核心:看存储的状态数)
  9. 核心逻辑:
  10. 分场景拆解
  11. 场景 1:一维 DP 原始版(斐波那契)
  12. 场景 2:一维 DP 空间优化版(斐波那契)
  13. 场景 3:二维 DP 原始版(最小路径和)
  14. 场景 4:二维 DP 空间优化版(最小路径和)
  15. 四、新手避坑点
  16. 五、典型 DP 问题复杂度总结(快速参考)
  17. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • RoboChallenge 发布具身智能年度报告:4 万次真机评测揭示模型真实能力
  • AI 时代核心概念解析:OpenClaw、Agent、Skill、Token 与 LLM
  • AI Agent 中的 Skills 是什么?有什么用?
  • 数据结构:二叉树经典习题讲解
  • Git 安装与基础配置指南
  • 从高原到云端:一名青海学子的 AI 农业创业实践
  • Stable Yogi 皮衣生成工具在动漫展会 VR 展厅的应用
  • AI 产品经理入门:大模型关键知识与落地逻辑
  • C++ 哈希表封装实战:模拟实现 unordered_map 与 unordered_set
  • Vue 组件开发中的枚举值验证:从 Type 属性错误说起
  • SpringBoot 核心模块 Java 源码规模统计
  • C++ 标准库 count 用法详解
  • 大模型推理中的张量并行:详解 4 种通信计算重叠模式
  • STC 单片机摄像头图像处理优化与搜线算法实战
  • Anaconda 环境变量 PYTHONPATH 设置:导入自定义 PyTorch 模块
  • C++ lower_bound 与 upper_bound 核心用法解析
  • YOLO13-C3k2-EIEM 改进算法:多年龄段人群图像识别技术
  • 基于 DeepSeek 与腾讯云 HAI 快速构建个人网页
  • VXE-Grid 表格 showOverflow Tooltip 不显示问题排查
  • 新兴人工智能 Agent 架构综述:推理、规划与工具调用

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online