动态规划2

把握要点:动态规划问题要注意保存子问题的值,并且在过程中,不要忘记使用它

经典面试题10
题目描述: 和第九题的框架相同,机器人还是要从网格左上角到达右下角,
但是网格中添加了障碍物,障碍物用1表示

  1. 状态定义:
    子状态从(0,0),(0,1),(1,0)…(m-1,n-1)的路径数
    F(i,j):从F(0,0)到F(i,j)的路径数
  2. **状态转移方程的定义:
    当这个点为0:F(i,j)=F(i,j-1)+F(i-1,j)
    当这个点位1:0 **
  3. 状态的初始化:F(i,0)=F(o,j)={0 OR 1}
  4. 返回结果:F(m-1,n-1)
    注意:如果此点为障碍物,则后面点都到达不了

public class Solution {
    public int uniquePathsWithObstacles(int[][] obstacles) {
         
        if(obstacles==null){
           return 0;
       }
       int m=obstacles.length;
       int n=obstacles[0].length;
       //用来储存每一个点的路径值
       int[][] temp=new int[m][n];
       //初始化,第一行,第一列的值若不为1(障碍),则到达的路径数为1
       for(int i=0;i<m;i++){
           if(obstacles[i][0]==1){
             break;
           }else {
               temp[i][0]=1;
           }
       }
        for(int j=0;j<n;j++){
            if(obstacles[0][j]==1){
                break;
            }else {
                temp[0][j]=1;
            }
        }
        for(int i=1;i<m;i++){
            for (int j=1;j<n;j++){
                if(obstacles[i][j]==1){
                //注意,此处是continue,只跳出本层循环
                    continue;
                }else {
                    temp[i][j]=temp[i-1][j]+temp[i][j-1];
                }
            }
        }
        return temp[m-1][n-1];
    }
}

经典面试题11
题目描述: 题目描述:
给定一个m*n的网格,网格用非负数填充,找到一条从左上角到右下角的最短路径。
注:每次只能向下或者向右移动。

  1. 状态定义:
    子状态从(0,0),(0,1),(1,0)…(m-1,n-1)的路径数
    F(i,j):从F(0,0)到F(i,j)的路径数
  2. 状态转移方程的定义:
    F(i,j)=min(F(i-1)(j),F(i)(j-1))+a[][j]
  3. 状态的初始化:F(0,0)=a(0,0)
    第一行:F(i,0)=F(i-1,0)+a[i][0]
    第一列:F(0,j)=F(0,j-1)+a[0][j]
  4. 返回结果:F(m-1,n-1)
public class Solution {
    public int minPathSum(int[][] grid) {
      if(grid==null){
            return 0;
        }
        int m=grid.length;
        int n=grid[0].length;
        int [][]temp=new int[m][n];
        //初始化
        temp[0][0]=grid[0][0];
        for(int i=1;i<m;i++){
            temp[i][0]=temp[i-1][0]+grid[i][0];
        }
        for(int j=1;j<n;j++){
            temp[0][j]=temp[0][j-1]+grid[0][j];
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                temp[i][j]=Math.min(temp[i-1][j],temp[i][j-1])+grid[i][j];
            }
        }
        return temp[m-1][n-1];   
    }
}

经典面试题12
题目描述: 题目描述:
有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小和数组 V 表示每个物品的价值.
问最多能装入背包的总价值是多大?

  1. 状态定义:
    F(i, j): 前i个物品放入大小为j的背包中所获得的最大价值
  2. 状态转移方程的定义:
    对于第i个商品:
    如果装不下:此时的价值与前i-1个的价值是一样的F(i,j) = F(i-1,j)
    如果可以装下:需要在两种选择中找最大的
    F(i, j) = max{F(i-1,j), F(i-1, j - A[i]) + V[i]}
    F(i-1,j): 表示不把第i个物品放入背包中, 所以它的价值就是前i-1个物品放入大小为j的背包的最大价值
    F(i-1, j - A[i]) + V[i]:表示把第i个物品放入背包中,价值增加V[i],但是需要腾出A[i]的大小放第i个商品
  3. 状态的初始化:F(0,0)=a(0,0)
    第0行和第0列都为0,(没有物品,没有容量)因此表示物品的价值都为0
    F(0,j) = F(i,0) = 0
  4. 返回结果:F(n,m)
public class Solution {
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @param V: Given n items with value V[i]
     * @return: The maximum value
     */
    public int backPackII(int m, int[] A, int[] V) {
        //运行条件,必须有值
        if(A==null&&V==null&&m<1){
            return 0;
        }
        //多开辟一行一列用于存储初始值,A的大小,m的大小都代表真实的值
        int N=A.length+1;
        int M=m+1;
        //存储背包的价值
        int [][] result=new int[N][M];
        //第0行(表示没有物品),第0列(表示没有背包容量),因此价值都为0,
           for(int i=0;i<N;i++){
               result[i][0]=0;
           }
           for(int j=0;j<M;j++){
               result[0][j]=0;
           }
           for(int i=1;i<N;i++){
               for(int j=1;j<M;j++){
                   //如果第i商品的重量大于背包的容量,放不下,所以(i,j)的最大价值和(i-1,j)相同
                   //注意边界,循环从1开始的,因此A[0]=A[1-1]
                   if(A[i-1]>j){
                       result[i][j]=result[i-1][j];
                   }else {
                       //否则要么装,要么不装
                       //装
                       int a=result[i-1][j-A[i-1]]+V[i-1];
                       //不装
                       int b=result[i-1][j];
                       //在装与不装之间选出最大值
                       result[i][j]=Math.max(a,b);
                   }
               }
           }
           //返回装入前N个商品,物品大小为m的最大价值
        return result[N-1][m];
    }
}

经典面试题13
题目描述: 题目描述:
给定一个字符串 s,把 s 分割成一系列的子串,分割的每一个子串都为回文串
返回最小的分割次数
比如,给定 s = “aab”,
返回1,因为一次cut就可以产生回文分割[“aa”,“b”]

  1. 状态定义:
    F(i): 前i个字符串的最小分割次数
  2. 状态转移方程的定义:
    F(i) = min(F(i), 1 + F(j) (j<i)
    上式表示如果从j+1到i判断为回文字符串,且已经知道从第1个字符
    到第j个字符的最小切割数,那么只需要再切一次,就可以保证
    1–>j, j+1–>i都为回文串。
  3. 状态的初始化:F(i)=i-1;(‘a’)不需要切割
  4. 返回结果:F(n)
public class Solution {
    public int minCut(String s) {
       if(s.isEmpty()){
            return 0;
        }
        int length=s.length();
        //用于储存到每个字母的最小分割次数
        int [] result=new int[length+1];
        //初始化,注意边界,0代表0个元素,
        for(int i=0;i<length+1;i++){
            result[i]=i-1;
        }
        for(int i=1;i<length+1;i++){
            for(int j=0;j<i;j++){
                ///F(i) = min{F(i), 1 + F(j)},
                //从最长串判断,如果从第j+1到i为回文字符串
                //则再加一次分割,从1到j,j+1到i的字符就全部分成了回文字符串
                if (isPalindrome(s, j, i - 1)){
                   result[i]=Math.min(result[i],1+result[j]);
                }
            }
        }

        return result[length];
    }

    private boolean isPalindrome(String s, int j, int i) {
        while(j<i){
            if(s.charAt(j)!=s.charAt(i)){
                return false;
            }
            j++;
            i--;
        }
        return true; 
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值