[Lintcode] triangle && 动态规划总结
2015-11-09 12:53
190 查看
Triangle
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.Example
For example, given the following triangle
[ [2], [3,4], [6,5,7], [4,1,8,3] ]
The minimum path sum from top to bottom is
11(i.e., 2 + 3 + 5 + 1 = 11).
Note
Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.
SOLUTION 1:
这个题特别适合总结DP方法,所以总结就在这题了。首先我们要知道为什么要动态规划,为啥不直接递归?很简单,递归时间复杂度太高了。为什么时间复杂度高?因为重复计算,实际上三角形里一共有(n^2)/2个点,实际算(n^2)/2次,O(n^2) 就够了,但是递归要计算多少次呢,递归要计算(2^n)/2,次,指数级别,太差了。怎么优化呢?cache一下就行了,现把所有计算结果放到hash里,然后重复计算时候就直接用,这样就只计算一次,就可以O(n^2)解决问题了。DP第一步就是这样,用记忆化搜索优化递归,达到DP效果。
记忆化搜索:这个方法我个人认为比DP好,不需要考虑转移方程,不需要考虑复杂的初始化,直接硬写,时间复杂度一样,多几行代码,少死几个脑细胞。
下面就是记忆化搜索模版:
核心就是先递归,做一个递归辅助函数,或者用divide & conquer也可以,写起来应该更简单。然后把所有结果存起来,如果flag标记一下,没标记过的存进去,标记过说明以前计算过,直接用,找到目标值就行了。
// 循环求所有状态 For I = 1 ->n dp[i] = search (i) // 搜索 int search(int i) { if(visit[i] == 1){ return dp[i]; } if(smallest state){ set smallest state } else { // to update (i,) , we might need other state // such as (i-1), (i+1) for other state update dp[i] = max(search(i-1) , search(i+1)) } visit[i] = 1; return dp[i]; }
看代码:
代码里用了几个全局变量,但是其实都是可以为了线程安全,放到search函数里。
// version 0: top-down public class Solution { /** * @param triangle: a list of lists of integers. * @return: An integer, minimum path sum. */ public int minimumTotal(int[][] triangle) { if (triangle == null || triangle.length == 0) { return -1; } if (triangle[0] == null || triangle[0].length == 0) { return -1; } // state: f[x][y] = minimum path value from 0,0 to x,y int n = triangle.length; int[][] f = new int ; // initialize f[0][0] = triangle[0][0]; for (int i = 1; i < n; i++) { f[i][0] = f[i - 1][0] + triangle[i][0]; f[i][i] = f[i - 1][i - 1] + triangle[i][i]; } // top down for (int i = 1; i < n; i++) { for (int j = 1; j < i; j++) { f[i][j] = Math.min(f[i - 1][j], f[i - 1][j - 1]) + triangle[i][j]; } } // answer int best = f[n - 1][0]; for (int i = 1; i < n; i++) { best = Math.min(best, f[n - 1][i]); } return best; } }
View Code
总结:
首先,在一个题里,看到问题是
**最大值/最小值**最大路径/最小路径**结果总数**true/false**=====> 基本可以先去试试动态规划思路。
其次,在动态规划过程中,可以优化的就是空间,用滚动数组优化二维DP,循环指针优化一维DP。(其实就是取个 %)。
再然后就是动态规划中,如果转移方程不好计算,并且初始化不好找,果断使用记忆化搜索,开一个额外空间做flag,标记这个位置是否访问过,再纪录所有计算过程,可以做到跟DP一样的时间复杂度。(我认为这个方法可以说是最好用的吧,不需要太多思考,但是一定要画一个搜索树,画图,确定方程)。
最后注意,比如说word ladder这种题,单词中字母位置跟DP数组中对应位置是否一致,需要看自己定义状态跟初始化。
相关文章推荐
- Object超类中Equals方法、toString方法和hashCode方法使用的举例
- Java集合框架体系
- React.js生态系统概览 [译]
- 如何查看lib文件的导出函数
- Java记录 -72- Vector,HashTable和Properties
- ubuntu 15.10 系统安装搜狗输入法的详细教程
- Maven为不同环境配置打包
- 高等数理统计(三)
- 连号区间数 (蓝桥杯)
- MySQL最基本的命令使用汇总
- centos7中一些command not found的解决方法
- 单纯BLOCK的执行
- Interfaces
- hrabs的数据库session的修改
- 编程之美-寻找发帖“水王”方法整理
- 重新获取货运号
- 黑马程序员-----反射
- Linux 下系统调用的三种方法
- beginEdit()和endEdit()到底用来干吗的?
- Mac OS X下安装Java 7及配置Eclipse JDK