1289 下降路径最小和【leetcode每日一题系列】

Alt
采用动态规划的思想来解决:题意中可以看出,数组的每一行取一个数,因此下一行的状态可以通过上一行的值来预测,具体分析如下:
ALT
如图所示为一个4*4的矩阵,我们定义 d p [ i ] [ j ] dp[i][j] dp[i][j]来表示选取矩阵中第i行第j列的数作为最后一个数,从而得到的非零偏移下降矩阵的最小值,则可知:

当i为0时,表示矩阵第一行, d p [ 0 ] [ j ] dp[0][j] dp[0][j]表示选取矩阵中第 0 0 0行第 j j j列的数作为最后一个数,则可知:
d p [ 0 ] [ j ] = g r i d [ 0 ] [ j ] dp[0][j] = grid[0][j] dp[0][j]=grid[0][j]

d p [ 0 ] dp[0] dp[0]的值为:
ALt
根据 d p [ 0 ] dp[0] dp[0]来寻找 d p [ 1 ] dp[1] dp[1],则 d p [ 1 ] [ 0 ] dp[1][0] dp[1][0]表示第一行的数字取 g r i d [ 1 ] [ 0 ] grid[1][0] grid[1][0]的非零偏移下降矩阵的最小值,则可知:

d p [ 1 ] [ 0 ] = m i n ( d p [ 0 ] [ 1 ] , d p [ 0 ] [ 2 ] , d p [ 0 ] [ 3 ] ) + g r i d [ 1 ] [ 0 ] dp[1][0] = min(dp[0][1],dp[0][2],dp[0][3])+grid[1][0] dp[1][0]=min(dp[0][1],dp[0][2],dp[0][3])+grid[1][0]

其他也可按照同理进行推断,总公式为:

d p [ 1 ] [ i ] = m i n ( d p [ 0 ] [ j ] ) + g r i d [ 1 ] [ i ] ,   j = 0 , 1 , . . . , n  且  j ! = i dp[1][i] = min(dp[0][j])+grid[1][i],\ j=0,1,...,n\ 且\ j!=i dp[1][i]=min(dp[0][j])+grid[1][i], j=0,1,...,n  j!=i

d p [ 1 ] dp[1] dp[1]的值为:
在这里插入图片描述
则可得递推公式为:

d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ k ] ) + g r i d [ i ] [ j ]   , k ! = j dp[i][j] =min(dp[i-1][k])+grid[i][j]\ ,k!=j dp[i][j]=min(dp[i1][k])+grid[i][j] ,k!=j

最后,遍历 d p [ n − 1 ] dp[n-1] dp[n1]找到最小值即可。
代码如下:

class Solution {
    public int minFallingPathSum(int[][] grid) {
        int n = grid.length;
        int[][] dp = new int[n][n];
        for(int i=0;i<n;i++){
            dp[0][i] = grid[0][i];
        }
        int row = 1, column = 0;
        while (row<n){
            while (column<n){
                int laxmin = Integer.MAX_VALUE;
                for(int i=0;i<n;i++){
                    if(i==column) continue;
                    laxmin = Math.min(laxmin,dp[row-1][i]);
                }
                dp[row][column] = laxmin + grid[row][column];
                column++;
            }
            System.out.println(" ");
            row++;
            column = 0;
        }
        int min = Integer.MAX_VALUE;
        for(int i=0;i<n;i++){
            min = Math.min(min,dp[n-1][i]);
        }
        return min;
 }

此代码的时间复杂度为 n 3 n^3 n3。由于在遍历时进行了重复遍历,每次寻找某行最小值时都需要遍历一遍上一行的值,增加了时间复杂度,可以先行记录下上一行的最小值 f i r s t m i n firstmin firstmin,最小值索引 f i r s t i n d e x firstindex firstindex以及次小值 s e c o n d m i n secondmin secondmin,则递推公式变为:

d p [ i ] [ j ] = { f i r s t m i n + g r i d [ i ] [ j ] , j ! = f i r s t i n d e x , s e c o n d m i n + g r i d [ i ] [ j ] , j = f i r s t i n d e x dp[i][j] =\left \{ \begin{array}{c} firstmin+grid[i][j],j!=firstindex, \\ \\ secondmin+grid[i][j],j=firstindex \end{array} \right. dp[i][j]= firstmin+grid[i][j],j!=firstindex,secondmin+grid[i][j],j=firstindex

即在每次寻找完 d p [ i ] dp[i] dp[i]之后,更新三个值即可,此时可使时间复杂度降为 n 2 n^2 n2,优化之后的代码如下:

class Solution {
    public int minFallingPathSum(int[][] grid) {
        int n = grid.length;
        int[][] dp = new int[n][n];
        for(int i=0;i<n;i++){
            dp[0][i] = grid[0][i];
        }
        int[] calcutate = findNumber(dp[0]);
        System.out.println(calcutate[0]);
        System.out.println(calcutate[2]);
        int length = 1, high = 0;
        while (length<n){
            while (high<n){
                if(high == calcutate[1]) dp[length][high] = calcutate[2] + grid[length][high];
                else dp[length][high] = calcutate[0] + grid[length][high];
                high++;
            }
            calcutate = findNumber(dp[length]);
            length++;
            high = 0;
        }
        return calcutate[0];
    }
    public int[] findNumber(int[] dp){
        int firstindex = -1;
        int firstmin = Integer.MAX_VALUE;
        int secondmin = Integer.MAX_VALUE;
        for(int i=0;i<dp.length;i++){
            if(secondmin>dp[i]){
                secondmin = dp[i];
                if(firstmin>secondmin){
                    int temp = firstmin;
                    firstmin = secondmin;
                    firstindex = i;
                    secondmin = temp;
                }
            }
        }
        return new int[]{firstmin,firstindex,secondmin};
    }
}
~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值