准备校招的!
这些是一本书的笔记-—程序员代码面试指南:IT名企算法与数据结构题目最优解(左程云)。
> **给定一个矩阵m,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,
路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和**。
> 【举例】如果给定的m如下:
> 1 3 5 9
> 8 1 3 4
> 5 0 6 1
> 8 8 4 0
路径1,3,1,0,6,1,0是所有路径中路径和最小的,所以返回12。
这正式进入动态规划的算法了!
经典动态规划方法。
假设矩阵m的大小为M×N,行数为M,列数为N。
先生成大小和m一样的矩阵dp,dp[i][j]的值表示从左上角(即(0,0))位置走到(i ,j)位置的最小路径和。
对m的第一行的所有位置来说,即(0,j)(0≤j<N),从(0,0)位置走到(0,j)位置只能向右走,
所以(0,0)位置到(0,j)位置的路径和就是m[0][0..j]这些值的累加结果。
同理,对m的第一列的所有位置来说,即(i,0)(0≤i<M),从(0,0)位置走到(i,0)位置只能向下走,
所以(0,0)位置到(i,0)位置的路径和就是m[0..i][0]这些值的累加结果。
以题目中的例子来说,dp第一行和第一列的值如下:
1 4 9 1 8
9
14
22
除第一行和第一列的其他位置(i ,j)外,
都有左边位置(i-1,j)和上边位置(i ,j-1)。从(0,0)到(i ,j)的路径必然经过位置(i-1,j)或位置(i ,j-1),
所以,dp[i][j]=min{dp[i-1][j],dp[i][j-1]}+m[i][j],含义是比较从(0,0)位置开始,
经过(i-1,j)位置最终到达(i,j)的最小路径和经过(i ,j-1)位置最终到达(i ,j)的最小路径之间
,哪条路径的路径和更小。 那么更小的路径和就是dp[i][j]的值。
以题目的例子来说,最终生成的dp矩阵如下:
1 4 9 18
9 5 8 12
14 5 11 12
22 13 15 12
除第一行和第一列之外,每一个位置都考虑从左边到达自己的路径和更小还是从上边达到自己的路径和更小。
最右下角的值就是整个问题的答案。具体过程请参看如下代码中的f方法。
依据上面的解析一步一步敲代码(自己敲出来才能很好理解):
public static int f(int[][] m){
//首先对矩阵m进行初步验证
if(m==null||m.length==0||m[0].length==0){
return 0;
}
int rows=m.length;//行
int cols=m[0].length;//列
/**
* dp[i][j]表示m[0][0]到m[i][j]的最短路径
*/
int[][] dp=new int[rows][cols];
dp[0][0]=m[0][0];
//第一行计算最短路径,只能向右走
for(int j=1;j<cols;j++){
dp[0][j]=dp[0][j-1]+m[0][j];
}
//第一列计算最短路径,只能向下走
for(int i=1;i<rows;i++){
dp[i][0]=dp[i-1][0]+m[i][0];
}
//计算dp[i][j]的值
for(int i = 1 ; i < rows ; i++){
for (int j = 1; j < cols; j++) {
dp[i][j]=Math.min(dp[i][j-1],dp[i-1][j])+m[i][j];
}
}
return dp[rows-1][cols-1];
}
测试:
public static void main(String[] args) {
int[][] m={{1,3,5,9},{8,1,3,4},{5,0,6,1},{8,8,4,0}};
System.out.println(f(m));
}
运行:
12
这种动态规划将问题一步一步分解,首先从最简单的情况开始–单行单列,其次依次增加复杂度,一步一步求解….
来个搞笑gif