动态规划/维特比算法----参考 吴军的《数学之美》,七月算法。
摘要:主要是从题目--二维数组路径最小和 的暴力枚举解法时间复杂度太高,贪心算法解法只能做到局部最优无法做到全局最优,从而引出动态规划,再到一个特殊但应用广泛的动态规划算法-维特比算法。
题目:二维数组路径最小和
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
1.暴力求解
m行n列的方格,从左上方走到右下方,每次只能向下或者向右走一步,如果枚举所有的可能路径 ,就是排列问题,要走m+n-2,其中n-1步是向下的,m-1步是向右的,时间复杂是C(m+n-2,n),当m和n非常大的时候,时间复杂度非常高,不适合,枚举不是万能的!
2.贪心算法
贪心算法就是每次在判断是要向右走或者向下走的时候,如果向下的值比较小,就向下走,否则向右走,也就是每次走的时候只判断当前到下一步,哪个比较小,就往哪里走,只能做到局部最优,没办法保证全局最优。
贪心的反例(图1):
1 |
5 |
6 |
2 |
100 |
7 |
100 |
15 |
4 |
14 |
12 |
3 |
13 |
11 |
10 |
这边从第一步出发的时候,有两种选择,向右5,向下2,2小于5,选择向下,但是2后面的只能选择100,而如果选择5,到达右下角的路径可以比100小很多。
3.动态规划
1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 |
理解动态规划的几个主要点:
(1)假设我们找到了一条从1到16的最短路径和的路线(路线一),假设它经过15,那么这条路线上的从1到15,必然也是从1到15最短的路径和的路径。假设不是,还能找到路线二可以使1到15更短,那么用路线二替换路线一,就可以找到一条经过15的从1到16的更短路径,这与我们讲的经过路线一的从1到16的路线是最短的路径相违背。
(2)在上面中我们假设已经找到了从1到16的最短路径,但是我们现在是要求从1到16的最短路径,因为从1到达16,肯定要经过12 /15中的一个,我们只要求出从1到12的最短路径和从1到15的最短路径,就可以找到从1到16的最短路径,而要找从1到15的最短路径,我们可以先找到从1到11或者14的最短路径........以此类推,我们要解决问题,可以先求子问题的解,要求子问题的解,我们可以先找到子子问题的解.......以此类推,直到子问题不可再拆解。
(3)从上面的分析我们可以得到递推式:dp[i][j]=Math.min(dp[i-1][j],dp[i][j-1])+grid[i][j],其中当j为0 的时候,dp[i][0]=grid[i][0]+dp[i-1][0],当j为0 的时候,dp[0][j]=grid[0][j]+dp[0][j-1].
输出代码如下:
public class Solution {
public int minPathSum(int[][] grid) {
int m=grid.length;
int n=grid[0].length;
int dp[][]=new int[m][n];
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(i==0){
if(j==0){
dp[i][j]=grid[i][j];
}else{
dp[i][j]=dp[i][j-1]+grid[i][j];
}
}else{
if(j==0){
dp[i][j]=dp[i-1][j]+grid[i][j];
}else{
dp[i][j]=Math.min(dp[i-1][j],dp[i][j-1])+grid[i][j];
}
}
}
}
return dp[m-1][n-1];
}
}
时间复杂度分析:因为只要两重循环,所以时间复杂度为O(m*n)
4.隐马尔科夫模型
待续。。。
5.维特比算法
待续。。。