❤️阅文后请用一句话总结您的心得和建议!动心请点赞❤️
整理自课程《重学数据结构与算法》
1、优化的最终目标
- 采用尽可能低的时间复杂度和空间复杂度,去完成一段代码的开发。
2、时间和空间的比较
-
假设一段代码经过优化后,虽然降低了时间复杂度,但依然需要消耗非常高的空间复杂度
- 举例:对于固定数据量的输入,这段代码需要消耗几十 G 的内存空间,很显然普通计算机根本无法完成这样的计算。如果一定要解决的话,一个最简单粗暴的办法就是,购买大量的高性能计算机,来弥补空间性能的不足。
-
假设一段代码经过优化后,依然需要消耗非常高的时间复杂度。
- 举例:对于固定数据量的输入,这段代码需要消耗 1 年的时间去完成计算。如果在跑程序的 1 年时间内,出现了断电、断网或者程序抛出异常等预期范围之外的问题,那很可能造成 1 年时间浪费的惨重后果。很显然,用 1 年的时间去跑一段代码,对开发者和运维者而言都是极不友好的。
-
发现问题:
- 如果是缺少计算空间,花钱买服务器就可以了。这是个花钱就能解决的问题。相反,如果是缺少计算时间,只能投入宝贵的人生去跑程序。即使你有再多的钱、再多的服务器,也是毫无用处。相比于空间复杂度,时间复杂度的降低就显得更加重要了。
-
结论:空间廉价,时间昂贵
3、数据结构连接时空
-
引例:假定在不限制时间、也不限制空间的情况下,你可以完成某个任务的代码的开发。这就是通常我们所说的暴力解法,更是程序优化的起点。
在 100 以内的正整数中,找到同时满足以下两个条件的最小数字:
(1)能被 3 整除
(2)除 5 余 2 -
暴力解法:从 1 开始到 100,每个数字都做一次判断。如果这个数字满足了上述两个条件,则返回结果。这是一种不计较任何时间复杂度或空间复杂度的、最直观的暴力解法。
-
程序优化降低复杂度:
- 最直观的想法:梳理程序,看其流程中是否有无效的计算或者无效的存储。
- 降低时间复杂度:递归、二分法、排序算法、动态规划等。
- 降低空间复杂度:核心思路就是,能用低复杂度的数据结构能解决问题,就千万不要用高复杂度的数据结构。
- 时空转换思想:通过某种方式,把时间复杂度转移到空间复杂度的话,就可以把无价的东西变成有价了。
- 举例:马路上的十字路口,所有车辆在通过红绿灯时需要分批次通行。这样,就消耗了所有车辆的通行时间。如果要降低这里的时间损耗,人们就想到了修建立交桥。修建立交桥后,每个可能的转弯或直行的行进路线,都有专属的一条公路支持。这样,车辆就不需要全部去等待红绿灯分批通行了。最终,实现了用空间换取时间。
- 思想迁移:程序开发可以借鉴这里的思想。在程序开发中,连接时间和空间的桥梁就是数据结构。对于一个开发任务,如果你能找到一种高效的数据组织方式,采用合理的数据结构的话,那就可以实现时间复杂度的再次降低。同样的,这通常会增加数据的存储量,也就是增加了空间复杂度。
-
总结:程序优化的核心思路
-
1、暴力解法。 在没有任何时间、空间约束下,完成代码任务的开发。
-
2、无效操作处理。 将代码中的无效计算、无效存储剔除,降低时间或空间复杂度。
-
3、时空转换。 设计合理数据结构,完成时间复杂度向空间复杂度的转移。
-
4、实例分析
- 题目一:假设有任意多张面额为 2 元、3 元、7 元的货币,现要用它们凑出 100 元,求总共有多少种可能性。
- 首先,来个暴力求解:
public void s2_1() {
int count = 0;
for (int i = 0; i < (100 / 7); i++) {
for (int j = 0; j < (100 / 3); j++