Dynamic Programming (iii) optimize the road to violence recursive - Digital Matrix and the minimum path

topic

Matrix m, starts from the top left or right can only go down, and finally reaches the position of the lower right corner, the paths of all the numbers add up and is the path, all paths return path and the minimum.

For example

Given m as follows:

1 3 5 9
8 1 3 4
5 0 6 1
8 8 4 0

1,3,1,0,6,1,0 path is the smallest of all paths and paths, the returned 12

Thinking

  1. Consider optimal substructure, which can be divided into sub-problems. From the beginning of the apex matrix, find the shortest path and, because only the down or right, you can consider two new situation, that point of view and the point right below the apex of two new matrix, just find both the minimum path matrix and then find out that the smaller, plus the value of the current vertex is the minimum path throughout the matrix and.
  2. After the recursive solution written, you will find overlapping sub-problems, it is suitable for regulatory action to solve the problem, as the excessive use of memory type recursion.
  3. Dependency analysis of the data memory can be defined in the order calculated, the calculated first value dependent gradually required to obtain the final value.

Recurrent violence

Fake code

minSum(int[][] arr, int x, int y)
    return arr[x][y] + Math.min(minSum(arr,x+1,y),minSum(arr,x,y+1));

The idea is very simple, the solution of the whole problem is to increase the value of the current position away form the right path and go down the smaller of.
x and y will keep increasing, reaches the last line of the boundary is x or y reaches the last one, so the code is rewritten as:

minSum(int[][] arr, int x, int y)
    int sum=0;
    if(x==arr.length-1)//到达右下角只有一条路可走
        for i=y...arr.length-1
            sum+=arr[x][i]
        return sum;
    if(y==arr.length-1)//到达右下角只有一条路可走
        for i=x...arr.length-1
            sum+=arr[i][y]
        return sum;
    return arr[x][y] + Math.min(minSum(arr,x+1,y),minSum(arr,x,y+1));

Java implementation

public class 数字矩阵的最小路径和 {
  public static int minSum(int[][] arr, int x, int y) {
    int sum = 0;
    if (x == arr.length - 1) {//到达右下角只有一条路可走
      for (int i = y; i < arr[0].length; i++) {
        sum += arr[x][i];
      }
      return sum;
    }
    if (y == arr[0].length - 1) {//到达右下角只有一条路可走
      for (int i = x; i < arr.length; i++) {
        sum += arr[i][y];
      }
      return sum;
    }
    return arr[x][y] + Math.min(minSum(arr, x + 1, y), minSum(arr, x, y + 1));
  }

  public static void main(String[] args) {
    System.out.println(minSum(new int[][]{
        {1, 3, 5, 9},
        {8, 1, 3, 4},
        {5, 0, 6, 1},
        {8, 8, 4, 0},
    },0,0));
  }
}

Search type memory

According to previous ideas presented, investigated changes in recursive function parameters, you can use a two-dimensional array to cache calculated values ​​is very simple, almost without thinking can be rewritten after the master routines:

  public static int minSumMemory(int[][] arr, int x, int y, int[][] map) {
    int sum = 0;
    if (x == arr.length - 1) {//到达右下角只有一条路可走
      for (int i = y; i < arr[0].length; i++) {
        sum += arr[x][i];
      }
      map[x][y] = sum; // 缓存
      return sum;
    }
    if (y == arr[0].length - 1) {//到达右下角只有一条路可走
      for (int i = x; i < arr.length; i++) {
        sum += arr[i][y];
      }
      map[x][y] = sum;//缓存
      return sum;
    }
    //=====判断缓存,没有值再递归,保证一个xy组合只计算一次=====
    int v1 = map[x + 1][y];
    if (v1 == 0)
      v1 = minSum(arr, x + 1, y);
    int v2 = map[x][y + 1];
    if (v2 == 0)
      v2 = minSum(arr, x, y + 1);

    sum = arr[x][y] + Math.min(v1, v2);
    map[x][y] = sum; // 缓存
    return sum;
  }

In general violence recursive exponential, memory type is recursive polynomial (two-dimensional matrix is ​​square grade) level, then rewrite the dynamic programming may not be able to improve efficiency, but because there is no use recursion, can reduce the risk of stack overflow .

Dynamic Programming

Before routine is proposed to study the process of obtaining the cache value, the current value to be cached recursive dependent on what value, the inverse process is over dynamic planning.

In this example, the cache table is a two-dimensional array, we eventually have to fill in every point value, which is the minimum path to reach this point and the lower right corner. Recursive top-down, bottom-up action can be regulated, from the x, y start boundary, i.e. the bottom row and rightmost column starts, as these points to only one path to the lower right corner, can be naturally solved.

            14
            5
            1
20  12  4   0

Then fill in the middle of the value of their own is very simple + = below and to the right of the small numbers, the final calculation of the 0-0 position, that is, the final answer:

12  11  13  14
16  8   8   5
12  7   7   1
20  12  4   0

Let's look at the code:

  public static int dp1(int[][] arr) {
    final int rows = arr.length;
    final int cols = arr[0].length;
    int[][] dp = new int[rows][cols];
    dp[rows - 1][cols - 1] = arr[rows - 1][cols - 1];
    //打表:最右一列
    for (int i = rows - 2; i >= 0; i--) {
      dp[i][cols - 1] = arr[i][cols - 1] + dp[i + 1][cols - 1];
    }
    //打表:最后一行
    for (int i = cols - 2; i >= 0; i--) {
      dp[rows - 1][i] = arr[rows - 1][i] + dp[rows - 1][i + 1];
    }
    for (int i = rows - 2; i >= 0; i--) {
      for (int j = cols - 2; j >= 0; j--) {
        dp[i][j] = arr[i][j]+Math.min(dp[i+1][j],dp[i][j+1]);
      }
    }
    return dp[0][0];
  }

Dp two-dimensional table, the minimum path can be restored:

Write pictures described here

This process is to find the smallest order from top left to bottom right corner, over the path to the original array to find the corresponding number just fine.

Space compression method: only one-dimensional arrays dp

The present embodiment simply return path and the minimum value, the required output path, the intermediate process without reservation. Consider a one-dimensional array to store the recursive values, calculated for each row covered on line, it has a value of 0-0 at a final figure on it.

For the present embodiment, since the same number of rows and columns, in which it is the size of the array is possible, if not, you can choose the number of rows or columns as the array size, of course, will change accordingly propulsion, in rows mode (number of rows more) to promote or column-wise (more columns) to advance.

Let us illustrate this process:

  1. dp=new int[4];The initial values ​​are all 0
  2. The source data to be updated [20 12 4 0], this time dp [i] represents a matrix from the (last row, i) and the minimum path end;
  3. Start Update Now let dp [I] from the smallest representative of the channel matrix (the penultimate line, i) and the end point, to update the last element, dp[3]=arr[倒数2行][最后一列]+dp[3];at this time becomes dp [20 12 4 1]; update dp [2]: dp[2] = arr[倒数第二行][倒数第二列]+min(4,1),. 4 is below the value 1 is the right value, so you can gradually update
  4. Repeat step 3 until the processing of the first row, returns dp [0] to

Code:

  /**
   * 空间压缩优化
   * @param arr
   * @return
   */
  public static int dp2(int[][] arr) {
    final int rows = arr.length;
    final int cols = arr[0].length;
    int N = 0;
    if (rows>=cols){
      N = cols;
    }
    int[] dp = new int[N];
    dp[N-1] = arr[rows - 1][N - 1];
    //打表:第一次更新
    for (int i = N - 2; i >= 0; i--) {
      dp[i] = arr[rows-1][i] + dp[i + 1];
    }
    // 行
    for (int i = rows-2; i >=0 ; i--) {
      dp[N-1]=arr[i][N-1]+dp[N-1];
      for (int j = N - 2; j >= 0; j--) {
        dp[j] = arr[i][j] + Math.min(dp[j],dp[j + 1]);
      }
      // Util.print(dp);
    }
    return dp[0];
  }

to sum up

This example of optimization routines can be applied to almost all the needs of two-dimensional dynamic programming table title by way of an array rollover certainly saves a lot of space.

But space compression method has limitations, the specific path that can not be undone optimal solution.

Reference books "Programmer Code Interview Guide."

Published 127 original articles · won 97 Like · views 310 000 +

Guess you like

Origin blog.csdn.net/zhengwei223/article/details/78763904