[Daily question] 1289. Minimum sum of descending paths II

[Daily question] 1289. Minimum sum of descending paths II

1289. Descent Path Min Sum II

topic description

Given you an nxn integer matrix grid, please return the minimum value of the sum of the digits of the non-zero offset descending path.

The non-zero offset descending path is defined as: select a number from each row in the grid array, and among the numbers selected in order, the adjacent numbers are not in the same column of the original array.

Example 1:

insert image description here

输入:grid = [[1,2,3],[4,5,6],[7,8,9]]
输出:13
解释:
所有非零偏移下降路径包括:
[1,5,9], [1,5,7], [1,6,7], [1,6,8],
[2,4,8], [2,4,9], [2,6,7], [2,6,8],
[3,4,8], [3,4,9], [3,5,7], [3,5,9]
下降路径中数字和最小的是 [1,5,7] ,所以答案是 13 。

Example 2:

输入:grid = [[7]]
输出:7

hint:

n == grid.length == grid[i].length
1 <= n <= 200
-99 <= grid[i][j] <= 99

problem solving ideas

Idea: The variant of the minimum sum of the descending path, dynamic programming + optimization. The difference between this question and the minimum sum of the descending path is that the current element of the minimum sum of the descending path can only come from the upper left corner, directly above, and upper right corner of the previous row, while the current element of this question cannot come from directly above. The most intuitive idea is to add a layer of loop to count the minimum value of the non-current column in the previous row, but the time complexity becomes O(N 3 ) , although C++ can also pass it.

int minFallingPathSum(vector<vector<int>>& grid) 
{
   int n=grid.size();
   if(n==1)
     return grid[n-1][n-1];
   //dp[i][j]表示第i行选择第j列累积的下降路径最小和
   vector<vector<long>> dp(n+2,vector<long>(n+2,0));
   //最左边和最右边两列需要赋值为INT_MAX 即不可选择对应行上的这些元素 特殊处理
   for(int k=1;k<=n;k++)
   {
     dp[k][0]=INT_MAX;
     dp[k][n+1]=INT_MAX;
   }
   long res=INT_MAX;
   for(int i=1;i<=n;i++)
   {
      for(int j=1;j<=n;j++)
      {
          long temp=INT_MAX;
          //加一层循环用于统计上一行的非当前列的最小值
          for(int k=1;k<=n;k++)
          {
             if(k!=j)
               temp=min(temp,dp[i-1][k]);
          }
          dp[i][j]=temp + grid[i-1][j-1];
          if(i==n) //最后一行 收集结果
            res=min(res,dp[i][j]);
       }
    }
    return res;
}

Optimization: Although the above O(n 3 ) time complexity can indeed be passed, there is still room for optimization. Because when calculating the minimum sum of the descending path corresponding to each element in the current row, it is necessary to calculate the minimum sum of the descending path of the non-current column in the previous row, so it needs to be calculated n times, many of which are repeated, so we need to optimize here. That is, think about how to calculate the minimum sum of the descending path of the non-current column in the previous row at one time? Calculating the minimum sum of the descending path of the non-current column in the previous row can actually be considered in two parts: if the current column of the previous row is not the minimum value, then directly take the minimum value of the previous row; if the current column of the previous row is the minimum value, then select the second smallest value of the previous row. That is to say, for each row, the minimum and second minimum values ​​of the current row and the subscript of the minimum value are recorded, so that they can be used in the next row, so that the O(N) time complexity of calculating the minimum sum of the descending paths of the non-current columns of the previous row is optimized to O(1) time complexity, that is, the overall O(N 3 ) time complexity is optimized to O( N 2 ) .

class Solution {
public:
    int minFallingPathSum(vector<vector<int>>& grid) {
        //要从上一行中选出最小值,但不能和当前数字在同一列,所以要考虑到同列的情况下用次小值
        int n=grid.size();
        if(n==1)
            return grid[n-1][n-1];
        //这一行下降和的最小值 这一行最小值对应的下标 这一行的次小值
        int first_sum=0,first_pos=-1,second_sum=0;  //上一轮的
        for(int i=0;i<n;i++) 
        {
            //记录这一行的最小值、最小值对应的下标、次小值
            int fs=INT_MAX,fp=-1,ss=INT_MAX;  //用于求当前的
            for(int j=0;j<n;j++)
            {
                int cur_sum=(first_pos!=j?first_sum:second_sum)+grid[i][j];
                if(cur_sum<fs)  //找到更小的
                {
                    ss=fs;   //将更小的赋值给次小的
                    fs=cur_sum;   //将当前的赋值给最小的
                    fp=j;   //记录最小对应的位置
                }
                else if(cur_sum<ss)  //不比最小小 比次小小 更新次小
                {
                    ss=cur_sum;
                }
            }
            //为下一行做准备
            first_sum=fs;
            first_pos=fp;
            second_sum=ss;
        }
        //最后一行最小值
        return first_sum;
    }
};

Guess you like

Origin blog.csdn.net/qq_43779149/article/details/131703658