前言
时隔这么久才发了这篇早在三周前就应该发出来的课堂笔记,由于懒癌犯了,加上各种原因,实在是应该反思。好多课堂上老师说的重要的东西可能细节上有一些急记不住了,但是幸好做了一些笔记,还能够让自己回想起来。动态规划算是我的一道大坎了,本科的时候就基本没有学过,研一的时候老师上课也是吃力的跟上了老师的步伐,其实那个时候老师总结的还是挺好的:把动态规划的题目都分成了一维动规、二维遍历、二维不遍历等一系列的问题。这次听了老师的课程,觉得还是需要更加集中的去把各种题进行一个分类吧,然后有针对的去准备,虽然据说这一块在面试中也不容易考到,但是毕竟是难点,还是需要好好准备一下的。因为在dp这个方面,我算是一个比较新手的新手,所以大家可以当作一起入门内容来看这篇博客。
Outline:
- 了解动态规划
- Triangle
- 动态规划的适用范围
- 坐标型动态规划
- Minimum Path Sum
- Climbing Stairs
- Jump Game
- Longest Increasing Subsequence
-
单序列动态规划
- Word Break
- 双序列动态规划
- Longest Common Subsequence
- 总结
课堂笔记
1.了解动态规划
就不过多的做解释了,直接来一个经典的题目。
给定一个数字三角形,找到从顶部到底部的最小路径和。每一步可以移动到下面一行的相邻数字上。
样例
比如,给出下列数字三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
从顶到底部的最小路径和为11 ( 2 + 3 + 5 + 1 = 11)。
拿到这个题目,如果不知道动态规划的话,想必大家第一反应就是遍历全部的路径,然后求出最小的值就可以。这个想法的话,跟二叉树的遍历有一点类似,但是大体还是不一样的,因为二叉树在分岔以后就各自保留子树,而这个题的不能考虑为二叉树的情况,这个结构可以画成如下的情况比较直观:
[2],
[3,4],
[6,5,7],
[4,1,8,3]
其中,2只能移动到3、4,3只能移动到6、5,同理,5只能移动到1,8……所以总结下来就是:当前的元素只能移动到下方和右下方的元素,即(i,j)只能移动到(i+1,j)或(i+1,j+1)。这样的话,DFS来做搜索就好了。
int bestans = INT_MAX; void travers(int i, int j, int sum, vector<vector<int> > &triangle) { if (i == triangle.size()) { // 遍历到最底层 bestans = bestans > sum ? sum : bestans; return; } travers(i + 1, j, sum + triangle[i][j], triangle); travers(i + 1, j + 1, sum + triangle[i][j], triangle); } int minimumTotal(vector<vector<int> > &triangle) { // write your code here travers(0, 0, 0, triangle); return bestans; }