题意描述:
有NxM大小的矩阵,从左上角走到右下角,只能向右,下,右下走,求到达右下角的最短带权路径长度
方法一:动态规划
采用递推的方式,定义一个二维数组,显然,的值就是从左上角走到的最短路径,要求从左上角到右下角的最短路径就是求的值
状态转移方程:
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param presentVolumn int整型二维数组 N*M的矩阵,每个元素是这个地板砖上的礼物体积 * @return int整型 */ public int selectPresent (int[][] presentVolumn) { // write code here int m=presentVolumn.length,n=presentVolumn[0].length; int[][]dp=new int[m][n]; dp[0][0]=presentVolumn[0][0]; int min=0; if(presentVolumn==null)return 0; for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ //第0行的元素由左边转移过来 if(i==0&&j>=1)dp[i][j]=dp[i][j-1]+presentVolumn[i][j]; //第0列的元素由上面的转移过来 else if(j==0&&i>=1)dp[i][j]=dp[i-1][j]+presentVolumn[i][j]; //非其余元素由左,上,左上的最小值转移过来 else if(i>=1&&j>=1){ dp[i][j]=Math.min(Math.min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1])+presentVolumn[i][j];} } } return dp[m-1][n-1]; } }
空间复杂度:
时间复杂度:外层循环次,内层循环次,总的时间复杂度为
空间复杂度:数组的空间大小为,空间复杂度为
优化方法
在原数组上做路径的更新,降低空间复杂度
具体代码如下:
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param presentVolumn int整型二维数组 N*M的矩阵,每个元素是这个地板砖上的礼物体积 * @return int整型 */ public int selectPresent (int[][] presentVolumn) { // write code here int m=presentVolumn.length,n=presentVolumn[0].length; if(presentVolumn==null)return 0; for(int j=1;j<n;j++)presentVolumn[0][j]+=presentVolumn[0][j-1]; for(int i=1;i<m;i++){ presentVolumn[i][0]+=presentVolumn[i-1][0]; for(int j=1;j<n;j++){ presentVolumn[i][j]+=Math.min(Math.min(presentVolumn[i-1][j],presentVolumn[i][j-1]),presentVolumn[i-1][j-1]); } } return presentVolumn[m-1][n-1]; } }
空间复杂度:
时间复杂度:外层循环次,内层循环次,平均时间复杂度为
空间复杂度:原地运算,空间复杂度为
方法二:记忆化搜索
递归公式为:
且:
且:
且:
且:
为了避免重复运算,使用记忆数组保存之前已经计算过的子问题,降低递归次数
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param presentVolumn int整型二维数组 N*M的矩阵,每个元素是这个地板砖上的礼物体积 * @return int整型 */ int[][]memory; public int selectPresent (int[][] presentVolumn) { // write code here int m=presentVolumn.length,n=presentVolumn[0].length; if(presentVolumn==null)return 0; memory=new int[m][n]; return dfs(m-1,n-1,presentVolumn); } int dfs(int i,int j,int[][]presentVolumn){ //递归终止条件 if(i==0&&j==0)return presentVolumn[0][0]; //已经计算过的直接返回 if(memory[i][j]!=0)return memory[i][j]; //除了[0,0]的第一行均由本身+左边得来 if(i==0&&j>0){ memory[i][j]=presentVolumn[i][j]+dfs(i,j-1,presentVolumn); return memory[i][j];} //除了[0,0]的第一列均由本身+上一个得来 else if(j==0&&i>0){ memory[i][j]=presentVolumn[i][j]+dfs(i-1,j,presentVolumn); return memory[i][j]; } //其他由本身+最小(上边,左上角,左边)得来 else{ memory[i][j]=presentVolumn[i][j]+Math.min(Math.min(dfs(i-1,j,presentVolumn),dfs(i-1,j-1,presentVolumn)),dfs(i,j-1,presentVolumn)); return memory[i][j]; } } }
复杂度:
时间复杂度:,递归次数不超过,每次递归地时间复杂度为常数级
空间复杂度:,递归栈和记忆数组的大小都不超过