您的位置:首页 > 其它

[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数组中对应位置是否一致,需要看自己定义状态跟初始化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: