[Algorithm]九章九之一:Matrix DP

109. Triangle:点击打开链接

方法一:自底向上

例如:从6开始,依赖于4和1中小者,再加上本身

注意:这种三角形第n行的长度是n+1,一共有n-1行,第0行的长度为1,

Time:O(n^2),而如果用DFS则需O(2^n),因此可知DP优化了很多

[
     [2],
    [3,4],
   [6,5,7],  
  [4,1,8,3]
]
[
    [2],
   [3,4], 
 [7,6,10],           遍历完最后一行,这一行成最后一行,相当于数组最后一行该加的数加上去后被弃掉,不断用本行最小的向上垒
[4, 1,8,3]
class Solution {
    public int rob(int[] nums) {
        if(nums == null || nums.length == 0)
        {
            return 0;
        }
        
        if(nums.length == 1)
        {
            return nums[0];
        }
        
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        dp[1]= Math.max(nums[0], nums[1]);
        
        for(int i=2; i<nums.length; i++)
        {
            dp[i] = Math.max(nums[i] + dp[i-2], dp[i-1]);
        }
        
        return dp[nums.length - 1];
    }
}
public class Solution {
    /**
     * @param triangle: a list of lists of integers.
     * @return: An integer, minimum path sum.
     */
    public int minimumTotal(int[][] triangle) {
        if(triangle==null || triangle.length==0){
            return 0;
        }
        if(triangle[0]==null || triangle[0].length==0){
            return 0;
        }
        
        int n=triangle.length;
        int[][] f=new int[n][n];
        
        for(int i=0;i<n;i++){                                            //因为是自底向上,初始化底部的每一个值
            f[n-1][i]=triangle[n-1][i];
        }
        
        for(int i=n-2;i>=0;i--){
            for(int j=0;j<=i;j++){
                f[i][j]=Math.min(f[i+1][j],f[i+1][j+1])+triangle[i][j];
            }
        }      
        return f[0][0];
    }
}
public class Solution {
    /**
     * @param triangle: a list of lists of integers.
     * @return: An integer, minimum path sum.
     */
    public int minimumTotal(int[][] triangle) {                         //和上面是一样的,只是写法上更容易理解
  
        if(triangle==null || triangle.length==0){
            return 0;
        }
        if(triangle[0]==null || triangle[0].length==0){
            return 0;
        }
        
        int n=triangle.length;
        for(int i=n-2;i>=0;i--){
            for(int j=0;j<=i;j++){
                triangle[i][j]=Math.min(triangle[i+1][j],triangle[i+1][j+1])+triangle[i][j];
            }
        }      
        return triangle[0][0];
    }
}
方法二:自顶向下
[
     [2],    [3,4],   [6,5,7],  [4,1,8,3]                 要初始化的值]
public class Solution {
    /**
     * @param triangle: a list of lists of integers.
     * @return: An integer, minimum path sum.
     */
    public int minimumTotal(int[][] triangle) {
        if(triangle==null || triangle.length==0){
            return 0;
        }
        if(triangle[0]==null || triangle[0].length==0){
            return 0;
        }
        
        int n=triangle.length;
        int[][] f=new int[n][n];
        f[0][0]=triangle[0][0];
        for(int i=1;i<n;i++){                                            //要初始化每一行第一个值和最后一个值
            f[i][0]=f[i-1][0]+triangle[i][0];
            f[i][i]=f[i-1][i-1]+triangle[i][i];
        }
        
        for(int i=1;i<n;i++){                                            //除了每一行第一个值和最后一个值
            for(int j=1;j<i;j++){
                f[i][j]=Math.min(f[i-1][j-1],f[i-1][j])+triangle[i][j];
            }
        }   
        
        int minVal=f[n-1][0];                                            //最后就是在f[][]的最后一行里找最小值
        for(int i=1;i<n;i++){
            minVal=Math.min(minVal,f[n-1][i]);
        }
        return minVal;
    }
}

LeetCode版本:点击打开链接

注意:set( )方法的使用

class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        if(triangle==null || triangle.size()==0){
            return 0;
        }
        
        int n=triangle.size();
        for(int i=n-2;i>=0;i--){
            for(int j=0;j<=i;j++){
                triangle.get(i).set(j,Math.min(triangle.get(i+1).get(j),triangle.get(i+1).get(j+1))+triangle.get(i).get(j));
            }            //这里的set方法,把j参数位置set成后面的内容
        }
        
        return triangle.get(0).get(0);    
    }
}

 

110. Minimum Path Sum: 点击打开链接

 

(0,0)(0,1)(0,2)(0,3)(0,4)
(1,0)(1,1)   
(2,0)    
(3,0)    
(4,0)   (4,4)

思路:由于同一时间只能向下或者向右移动一步,所以(1,1)是它的上面的(0,1)和左面的(1,0)走过来的

         但是最上面一行没有上面,最左面一行没有左面,因此f[i][0]和f[0][i]是要初始化值的

         直到走到(4,4),它是f[R-1][C-1]

注意:一般地,初始化一个二维动态规划时,就去初始化第0行第0列

public class Solution {
    /**
     * @param grid: a list of lists of integers.
     * @return: An integer, minimizes the sum of all numbers along its path
     */
    public int minPathSum(int[][] grid) {
        if(grid==null || grid.length==0){
            return 0;
        }
        if(grid[0]==null || grid[0].length==0){
            return 0;
        }
        
        int R=grid.length;
        int C=grid[0].length;
        int[][] f=new int[R][C];
        
        f[0][0]=grid[0][0];                         //f[0][0]的情况
        for(int i=1;i<R;i++){                       //第0行和第0列初始化的时候也不都是仅仅抄写原来的值
            f[i][0]=f[i-1][0]+grid[i][0];           //比方本题,是从最左上方向最右下方走
        }
        for(int i=1;i<C;i++){                       //第0行有一个向右的指向
            f[0][i]=f[0][i-1]+grid[0][i];           //第0列有一个向下的指向
        }
        
        for(int i=1;i<R;i++){
            for(int j=1;j<C;j++){
                f[i][j]=Math.min(f[i-1][j],f[i][j-1])+grid[i][j];
            }
        }
        return f[R-1][C-1];
    }
}

114.Unique Paths:点击打开链接

 

(0,0)(0,1)(0,2)(0,3)(0,4)
(1,0)(1,1)   
(2,0)    
(3,0)   (3,4)
(4,0)  (4,3)(4,4)
11111
1234 
136  
14   
1    

思路:(1,1)点的2种方案是上一次(0,1)和(1,0)的每1种走法造成的结果

         因此可知,(4,4)点的方案种数是上一次(3,4)和(4,3)的种数走法造成的结果

 

public class Solution {
    /**
     * @param n, m: positive integer (1 <= n ,m <= 100)
     * @return an integer
     */
    public int uniquePaths(int m, int n) {
        if(m==0 || n==0){                       //当只有一行或者一列的时候,只有一种方案,恒或者竖着一根线走到底
            return 1;
        }
        
        int[][] f=new int[m][n];
        for(int i=0;i<m;i++){                   //由于f[0][0]=1,因此没有单独记录f[0][0]的情况
            f[i][0]=1;
        }
        for(int i=0;i<n;i++){
            f[0][i]=1;
        }
        
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                f[i][j]=f[i-1][j]+f[i][j-1];
            }
        }
        return f[m-1][n-1];
    }
}

115.Unique Paths II:点击打开链接

思路:Unique Path的follow up,设置了障碍,只要把障碍处的方案种数记录为0即可。

public class Solution {
    /**
     * @param obstacleGrid: A list of lists of integers
     * @return: An integer
     */
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        if(obstacleGrid==null || obstacleGrid.length==0){
            return 0;
        }
        if(obstacleGrid[0]==null || obstacleGrid[0].length==0){
            return 0;
        }
        
        int R=obstacleGrid.length;
        int C=obstacleGrid[0].length;
        int[][] f=new int[R][C];
        
        for(int i=0;i<R;i++){                     //第一竖行有障碍的情况,只要有障碍下面的都走不到,因此break
            if(obstacleGrid[i][0]!=1){
                f[i][0]=1;
            }else{
                break;
            }    
        }
        for(int i=0;i<C;i++){                     //第一横行有障碍的情况,只要有障碍后面的都走不到,因此break
            if(obstacleGrid[0][i]!=1){
                f[0][i]=1;
            }else{
                break;
            }    
        }
        
        for(int i=1;i<R;i++){
            for(int j=1;j<C;j++){
                if(obstacleGrid[i][j]!=1){        
                    f[i][j]=f[i-1][j]+f[i][j-1];
                }else{                            //但是其他位置有障碍的情况,这个位置后面的和下面的还可以被走到
                    f[i][j]=0;                    //因此只把这个位置的f[i][j]记为0,不能break
                }
            }
        }
        return f[R-1][C-1];
    }
}

111.Climbing Stairs:点击打开链接

思路:爬楼梯题目介于Matrix和Sequence之间,用一维数组解决

解释:因为第三层台阶也就是f[2]是由第一层台阶f[0]或者第二层台阶f[1]跳上去的,所以f[2]=f[1]+f[0]

public class Solution {
    /**
     * @param n: An integer
     * @return: An integer
     */
    public int climbStairs(int n) {
        int[] f=new int[n];
        if(n<2){                          //特殊情况先return值
            return 1;
        }
        
        f[0]=1;                           //初始化第一层的值
        f[1]=2;                           //初始化第二层的值
       
        for(int i=2;i<n;i++){             //从第三层开始
            f[i]=f[i-1]+f[i-2];           //因为要用到第一层和第二层记录的数据
        }
        return f[n-1];
    }
}

272.Climbing Stairs II:点击打开链接

public class Solution {
    /**
     * @param n an integer
     * @return an integer
     */
    public int climbStairs2(int n) {
        int[] f=new int[n];
        if(n<2){
            return 1;
        }
        if(n==2){
            return 2;
        }
        f[0]=1;                          //初始化第一层的值
        f[1]=2;                          //初始化第二层的值
        f[2]=4;                          //初始化第三层的值
        for(int i=3;i<n;i++){            //从第四层开始,之后都符合规律
            f[i]=f[i-1]+f[i-2]+f[i-3];
        }      
        return f[n-1];
        
    }
}

630. Knight Shortest Path II:点击打开链接

方法二:BFS

思路:和Knight Shortest Path思路是一毛一样的,只是限制了马的走位,只留下右边的4个,起点是(0,0),终点是(n-1,m-1)

class Point {                                                         //自己写的内部类不可以加public,
      public int x,y;                                                 //要不然就写在一个新file,名为Point里
      public Point() {x=0;y=0;}
      public Point(int x, int y) {
          this.x=x;
          this.y=y;
      }
}

public class Solution {
    /**
     * @param grid a chessboard included 0 and 1
     * @return the shortest path
     */
    public int[] deltaX={1,-1,2,-2};
    public int[] deltaY={2,2,1,1};
    public int shortestPath2(boolean[][] grid) {
        if(grid==null || grid.length==0){
            return -1;
        }
        
        Point start=new Point(0,0);
        Point end=new Point(grid.length-1,grid[0].length-1);
        Queue<Point> queue=new LinkedList<>();
        queue.offer(start);
        int steps=0;
        
        while(!queue.isEmpty()){
            int size=queue.size();
            for(int i=0;i<size;i++){
                Point point=queue.poll();
                if(point.x==end.x && point.y==end.y){
                    return steps;
                }
                for(int direction=0;direction<4;direction++){
                    Point movePoint=new Point(point.x+deltaX[direction],
                                              point.y+deltaY[direction]);
                    if(isValid(grid, movePoint)){
                        queue.offer(movePoint);
                        grid[movePoint.x][movePoint.y]=true;
                    }
                }
            }
            steps++;
        }
        return -1;
    }
    
    private boolean isValid(boolean[][] grid, Point point){
        if (point.x < 0 || point.x >= grid.length) {
            return false;
        }
        if (point.y < 0 || point.y >= grid[0].length) {
            return false;
        }
        return grid[point.x][point.y] == false;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值