动态规划二丶坐标型,序列型

1.坐标型动态规划:

1.1介绍:

在这里插入图片描述

1.2例题:

1.2.1:例1.

在这里插入图片描述

在这里插入图片描述

public int uniquePathsWithObstacles(int[][] A){
        int m = A.length;  //表示行数
        if(m==0){
            return 0;
        }
        int n =A[0].length;//表示列数
        if(n==0){
            return 0;
        }
        int [][] f = new int[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j <n ; j++) {
                if(A[i][j]==1){  //如果是障碍物的话
                    f[i][j]=0;
                }
                else{
                    if(i==0&&j==0){ //初始条件,如果只有一行或者只有一列
                        f[i][j]=1;
                    }
                }
                else{
                
//                    if(i==0) f[i][j]=f[i][j-1];
   //下面的这种写法其实 和f[i][j]=f[i-1][j]+f[i][j-1];一样,让后加了上面的这种初始条件而已。
                    f[i][j]=0;
                    if(i-1>=0){
                        f[i][j]+=f[i-1][j];
                    }
                    if(j-1>=0){
                        f[i][j]+=f[i][j-1];
                    }
                }
            }
        }
        return f[i][j];
    }
1.2.2 例2

在这里插入图片描述
在这里插入图片描述
确定状态:
在这里插入图片描述
子问题:
在这里插入图片描述
转移方程:
在这里插入图片描述

 public class Solution{
        int result =0;
        void calc(int[] A,int n){
            int[] f =new int[n];
            for (int i = 0; i <n ; i++) {
                //情况1:最长连续上升子序列就是最后一个元素。
                f[i]=1;
                //情况2;子序列的长度大于1.
                if(i>0&&A[i-1]<A[i]){
                    f[i]=f[i-1]+1;
                }
                if(f[i]>result){
                    result=f[i];
                }
            }
        }
        public int longestIncreasingCotinuousSubsequence(int[] A){
            int n = A.length;
            if(n==0){
                return 0;
            }
            calc(A,n);  //先看顺序,
            int i,j,t;
            i=0;
            j=n-1;
            while(i<j){
                t=A[i];
                A[i]=A[j];
                A[j]=t;
                ++i;
                --j;
            }
            calc(A,n);  //然后在看倒序。
            return result;
        }
    }

2.序列型动态规划:

在这里插入图片描述
确定状态的时候:
在这里插入图片描述
子问题:注意:序列型和坐标之间的转换,

例如:数组A={0,1,2}中,前3项就表示的是0,1,2 。     i-1:就表示最后一项为2

在这里插入图片描述
状态转移方程:
在这里插入图片描述
同理可得:
在这里插入图片描述
初始条件和边界情况:
在这里插入图片描述
计算顺序:
在这里插入图片描述

public int minCost(int[][] cost){
      //f[i][j]:是表示的前i栋房子,最后一个房子染成j这种颜色
      int res;
      int n=cost.length;
      if(n==0){
          return 0;
      }
      int[][] f =new int[n+1][3];  //其中3代表3种颜色。n+1: f[0]...f[n]
      f[0][0]=f[0][1]=f[0][2]=0; //初始条件中没有房子的话,花费都是0;
      for (int i = 0; i <=n ; i++) {
          //j:是i-1房子的颜色
          for (int j = 0; j <3 ; j++) {  //视频中是++j。后面有机会看下我这种写法对不对
              f[i][j]=Integer.MAX_VALUE; //与之前的题类似先给一个最值,
              //K:是i-2房子的颜色
              for (int k = 0; k <3 ; k++) {  //视频中是++k。后面有机会看下我这种写法对不对
                  //上一个房子的颜色和这个房子的颜色不能一样。
                  if(j==k){
                      continue;
                  }
                  //这里是在找最小值,然后去替代他。
                  //f[i-1][k]:前i-1栋房子,且最后一个房子为K这种颜色。cost[i-1][j]:坐标上i-1栋房子的花费。始终:后者为前者的后面一个房子。
                  if(f[i-1][k]+cost[i-1][j]<f[i][j]){
                      f[i][j]=f[i-1][k]+cost[i-1][j];
                  }
              }

          }
      }
      res=Math.min(f[n][0],f[n][1],f[n][2]);

      return res;
  }

总结:
在这里插入图片描述

3划分型动态规划

在这里插入图片描述
确定状态:
在这里插入图片描述
在这里插入图片描述
子问题:
在这里插入图片描述
转移方程:
注意:序列型和划分性:都是前i个,最后一个是i-1.
在这里插入图片描述
初始条件和边界条件:
在这里插入图片描述

   public int numDecodings(String ss){
       char[] s = ss.toCharArray();
       int n = s.length;
       if(n==0){
           return 0;
       }
       int[] f =new int[n+1];
       f[0]=1;
       for (int i = 1; i <=n ; i++) {
           f[i] =0;
           //最后一个数字
           int t =s[i-1]-'0';
           if(t>=1&&t<=9){
               f[i]+=f[i-1];
               
           }
           //长度必须大于1
           if(i>=2){
               //倒数第2个数字。
               t=(s[i-1]-'0')*10+(s[i-1]-'0');
               if(t>=10&&t<=26){
                   f[i]+=f[i-2];
               }
           }
       }
       return f[n];
   }

4.最值型动态规划

4.1例1

在这里插入图片描述
确定状态:
在这里插入图片描述
在这里插入图片描述
转移方程:
在这里插入图片描述
初始条件和边界条件:
在这里插入图片描述

 public static int minPathSum(int[][] A){
		if(A==null ||A.length==0||A[0].length==0){
			return 0;
			}
        int m=A.length;
        int n=A[0].length;
        int[][] f = new int[2][n]; //这里使用的是滚动数组
        int old =1,now =0;
        int t1,t2;
        for (int i = 0; i <m ; i++) {
            old =now;
            now =1-old;
            for (int j = 0; j <n ; j++) {
                if(i==0&&j==0){  //初始条件:只有(0,0)的时候才满足条件。
                    f[now][j] =A[i][j];
                    continue;
                }
                f[now][j] =A[i][j];
                if(i>0){
                     t1=f[old][j];
                }else{
                     t1=Integer.MAX_VALUE;
                }
                if(j>0){
                    t2=f[now][j-1];
                }else{
                    t2=Integer.MAX_VALUE;
                }
                if(t1<t2){
                    f[i][j]+=t1;
                }else{
                    f[now][j]+=t2;
                }
            }
        }
        return f[now][n-1];
    }

4.2 例2:

在这里插入图片描述
其中的E:表示敌人,W:表示墙, 0:表示空格子。
确定状态:
在这里插入图片描述
子问题:
在这里插入图片描述
初始条件和边界条件
在这里插入图片描述
四个方向:
在这里插入图片描述

 public int maxKilledEnemies(char[][] A){
        if(A==null||A.length==0||A.length==1&&A[0].length==0){
            return 0;
        }
        int m =A.length;
        int n=A[0].length;
        int[][] f =new int[m][n];  //用来更新每次上下左右的值
        int[][] res =new int[m][n]; //用来保存,这个格子能炸死敌人的数目
        for (int i = 0; i < m; i++) {
            for (int j = 0; j <n ; j++) {
                res[i][j]=0;
            }
        }
        //计算当前格子“向上”
        for (int i = 0; i <m ; i++) {
            for (int j = 0; j < n; j++) {
                if(A[i][j]=='W'){
                    f[i][j]=0;
                }else{
                    f[i][j]=0;
                    if(A[i][j]='E'){
                        f[i][j]=1;
                    }
                    if(i>0){
                        f[i][j]+=f[i-1][j];
                    }
                }
                res[i][j]+=f[i][j];
            }
        }
        //计算当前格子“向下”
        for (int i = m-1; i >=0 ; i++) {
            for (int j = 0; j < n; j++) {
                if(A[i][j]=='W'){
                    f[i][j]=0;
                }else{
                    f[i][j]=0;
                    if(A[i][j]='E'){
                        f[i][j]=1;
                    }
                    if(i+1<m){
                        f[i][j]+=f[i+1][j];
                    }
                }
                res[i][j]+=f[i][j];
            }
        }
        //计算当前格子“向左”
        for (int i = 0; i <m ; i++) {
            for (int j = 0; j < n; j++) {
                if(A[i][j]=='W'){
                    f[i][j]=0;
                }else{
                    f[i][j]=0;
                    if(A[i][j]='E'){
                        f[i][j]=1;
                    }
                    if(j-1>=0){
                        f[i][j]+=f[i][j-1];
                    }
                }

                res[i][j]+=f[i][j];
            }
        }
        //计算当前格子“向右”
        for (int i = 0; i <m ; i++) {
            for (int j =n-1; j >=0; j++) {
                if(A[i][j]=='W'){
                    f[i][j]=0;
                }else{
                    f[i][j]=0;
                    if(A[i][j]='E'){
                        f[i][j]=1;
                    }
                    if(j+1<n){
                        f[i][j]+=f[i][j+1];
                    }
                }
                res[i][j]+=f[i][j];
            }
        }
        int result =0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if(A[i][j]=='0'){  //因为只有‘0’的地方才可以安放炸弹。
                    if(res[i][j]>result){
                        result=res[i][j];
                    }
                }
            }
        }
        return result;
    }

知识点:

1.判断二维数组是否为空:

在这里插入图片描述

2.空间优化:

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值