下面按照具体的分类来刷题,总结每个思想的精髓。
递归 🚶🚶🚶🚶
解决问题的过程中,需要经过多个决策阶段,每个决策都会对应一个状态。我们寻找一组决策序列,经过这组决策序列,能够产生最终期望的最优值。我们把这种问题模型称为多阶段决策最优解模型. DP,回溯,贪心都可以解决这类问题.
利用动态规划解决的问题,需要满足三个特征:
- 最优子结构, 就是说后面的状态可以通过前面的状态推导出来
- 无后效性, 就是说一旦状态确定,就不会更改
- 重复子问题, 就是说不同的决策序列,到达某个相同的阶段时,可能会产生不同的状态。
贪心算法实际上是DP的一种特殊情况,它能解决的问题更加有限。需要满足三个条件:
- 最优子结构
- 无后效性
- 贪心选择性, 意思就是局部最优选择,能产生全局最优选择。
所以贪心算法能否解决算法问题的关键在于: 局部最优能不能达到全局最优?
回溯算法是”万金油“。基本上贪心和dp能解决的问题,回溯都能解决。回溯相当于穷举搜索,列举出所有的情况,然后对比得到最优解。不过回溯的复杂度一般都是指数级的,只能用来解决小规模数据的问题。
数组有两个关键词:
- 线性表结构, 就是说元素之间只有前后关系
- 连续的内存空间,存储的是具有相同类型的数据
第二个特征决定了数组“随机访问”的能力,因为我们完全可以通过地址计算出下标对应的位置。比如:
a[i]_add = base_add + i * type_size
有利就有弊,也正是由于内存连续,所以数组的插入和删除是非常低效的,因为为了保持内存的连续,就意味着每次插入/删除都要伴随着大量的移动操作,平均负责度为o(n).
容器类在数组的基础上,封装了插入删除等操作,同时支持了动态扩容. 需要注意的是,如果实现知道数组的大小,最好提前指定容器大小,这样可以省掉多次的内存申请和数据搬移。
大多情况下的解题思路:
- 双指针
- DP
- 二分查找