Roshin's blog Roshin's blog
首页
  • 《数据结构与算法》笔记
  • 手写代码
  • 实用方法
  • 文档教程
  • 面试集锦
  • 分类
  • 标签
  • 归档
  • 个人介绍
  • 关于博客
  • 友情链接
GitHub (opens new window)

Roshin

如果你只做自己能力范围之内的事情,就永远没法进步。
首页
  • 《数据结构与算法》笔记
  • 手写代码
  • 实用方法
  • 文档教程
  • 面试集锦
  • 分类
  • 标签
  • 归档
  • 个人介绍
  • 关于博客
  • 友情链接
GitHub (opens new window)
  • 如何衡量程序运行的效率?
  • 将“昂贵”的时间复杂度转换成“廉价”的空间复杂度
    • 时间昂贵、空间廉价
    • 程序开发中复杂度降低的核心方法论
    • 示例
    • 练习
  • 《数据结构与算法》笔记
roshin
2021-03-19

将“昂贵”的时间复杂度转换成“廉价”的空间复杂度

笔记

代码效率优化就是要将可行解提高到更优解,最终目标是:要采用尽可能低的时间复杂度和空间复杂度,去完成一段代码的开发。

时间昂贵、空间廉价 #

代码效率的瓶颈可能发生在时间或者空间两个方面。如果是缺少计算空间,花钱买服务器就可以了。这是个花钱就能解决的问题。相反,如果是缺少计算时间,只能投入宝贵的人生去跑程序。即使你有再多的钱、再多的服务器,也是毫无用处。相比于空间复杂度,时间复杂度的降低就显得更加重要了。

结论:空间是廉价的,而时间是昂贵的。

降低空间复杂度的核心思路就是:能用低复杂度的数据结构能解决问题,就千万不要用高复杂度的数据结构。

程序开发中复杂度降低的核心方法论 #

  1. 暴力解法:在没有任何时间、空间约束下,完成代码任务的开发

    先解决问题

  2. 无效操作处理:将代码中的无效计算、无效存储剔除,降低时间或空间复杂度

    学会并掌握递归、二分法、排序算法、动态规划等常用的算法思维

  3. 时空转换:设计合理数据结构,完成时间复杂度向空间复杂度的转移

    对数据的操作进行细分,全面掌握常见数据结构的基础知识

示例 #

  1. 假设有任意多张面额为 2 元、3 元、7 元的货币,现要用它们凑出 100 元,求总共有多少种可能性
暴力解法

代码共执行n + n² + n³次,则f(n) = n³。时间复杂度为O(n³)

function fn(n = 100) {
  let count = 0;
  for (let i = 0; i <= n / 7; i++) {
    for (let j = 0; j <= n / 3; j++) {
      for (let k = 0; k <= n / 2; k++) {
        if (i * 7 + j * 3 + k * 2 === n) {
          count += 1;
        }
      }
    }
  }
  return count;
}
1
2
3
4
5
6
7
8
9
10
11
12
代码优化

代码共执行n + n²次,则f(n) = n²。时间复杂度为O(n²)

function fn(n = 100) {
  let count = 0;
  for (let i = 0; i <= n / 7; i++) {
    for (let j = 0; j <= n / 3; j++) {
      if (n - i * 7 - j * 3 >= 0 && (n - i * 7 - j * 3) % 2 === 0) {
        count += 1;
      }
    }
  }
  return count;
}
1
2
3
4
5
6
7
8
9
10
  1. 查找出一个数组中,出现次数最多的那个元素的数值
暴力解法

代码共执行n + n²次,则f(n) = n²。时间复杂度为O(n²)

function fn(arr = [1, 2, 3, 4, 5, 5, 6]) {
  let val_max = 1;
  let time_max = 0;
  for (let i = 0; i < arr.length; i++) {
    let time_tmp = 0;
    for (let j = 0; j < arr.length; j++) {
      if (arr[i] === arr[j]) {
        time_tmp += 1;
      }
      if (time_tmp > time_max) {
        time_max = time_tmp;
        val_max = arr[i];
      }
    }
  }
  return val_max;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
代码优化

通过采用更复杂、高效的数据结构,完成了时空转移,提高了空间复杂度O(n),降低了时间复杂度O(n)

function fn(arr = [1, 2, 3, 4, 5, 5, 6]) {
  const map = new Map();
  for (let i = 0; i < arr.length; i++) {
    // 实现数组转字典
    if (map.has(arr[i])) {
      map.set(arr[i], map.get(arr[i]) + 1);
    } else {
      map.set(arr[i], 1);
    }
  }

  let val_max = -1;
  let time_max = 0;
  for (const key of map.keys()) {
    if (map.get(key) > time_max) {
      time_max = map.get(key);
      val_max = key;
    }
  }
  return val_max;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

练习 #

示例 1 中是否存在更优的解法?如果有,请写出来

答案解析

第 4 行代码,j 需要遍历到 33。但很显然,随着 i 的变大,j 并不需要遍历到 33。例如,当 i 为 9 的时候,j 最大也只能取到 12。如果 j 大于 12,则 7 * 9 + 3 * 13 > 100。虽然减少了循环次数,但是时间复杂度并没有降低,因为 j 的取值范围也是与 n 线性相关的




 







function fn(n = 100) {
  let count = 0;
  for (let i = 0; i <= n / 7; i++) {
    for (let j = 0; j <= (n - 7 * i) / 3; j++) {
      if (n - i * 7 - j * 3 >= 0 && (n - i * 7 - j * 3) % 2 === 0) {
        count += 1;
      }
    }
  }
  return count;
}
1
2
3
4
5
6
7
8
9
10
编辑 (opens new window)
上次更新: 2021-06-23 08:43:55
如何衡量程序运行的效率?

← 如何衡量程序运行的效率?

最近更新
01
函数柯里化
04-15
02
Array.prototype.flat()
04-14
03
Array.prototype.reduce()
04-14
更多文章>
Theme by Vdoing Copyright © 2021-present Roshin | MIT License | 粤ICP备18116277号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式