动态规划合集(各个类型+LeetCode)

由于提供的内容仅为'zzz',缺乏关键信息,无法生成有效摘要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

zzz

1.零钱兑换(322):求最值

一:确定状态:
	)1:最终状态:要想达到用最少数量k的硬币凑出目标值n,则前面的k-1需要凑出n-ak,且k-1的数量一定是最少的
	)2:子问题:最少用多少枚硬币可以凑出n-ak
二:转移方程: f(i)= min(f(i),f(i-coin(j))+1)
三:初始条件和边界条件:f(0= 0
四:计算顺序:由下到上


/*
执行用时:15 ms, 在所有 Java 提交中击败了69.31%的用户
内存消耗:39.2 MB, 在所有 Java 提交中击败了5.77%的用户
*/
class Solution {
 public int coinChange(int[] coins, int amount) {
        if(amount==0) return 0;
        //dp[i]:当amount为i时,凑成i的最小硬币使用数
        int[] dp = new int[amount+1];
        //初始值,可以的取值范围是[amount+1,Integer.MAX_VALUE)
        Arrays.fill(dp,amount+1);
        dp[0] = 0;
        for (int i =1;i<=amount;i++){
            for (int j = 0;j<coins.length;j++){
                if(i-coins[j]<0) continue;
                dp[i] = Math.min(dp[i],dp[i-coins[j]]+1);
            }
        }
        return dp[amount]==amount+1?-1:dp[amount];
    }
}
2.零钱兑换 II(518):求计数

一:确定状态:
	)1:最终状态:凑成总值为n的方法数,等于凑成总值为n-coin[k](0<=k<=coin.length-1)的方法的总和。
	)2:子问题:凑出n-coin[k]的方法数
二:转移方程:f(i)=f(i-coin[0]+...+f(i-coin[coin.length-1])
        即f(i)= f(i)+f(i-coin[k])
三:初始条件和边界条件:当总金额为0时,方法数为1;没有硬币时,方法数为0
四:计算顺序:从下到上


/*
执行用时:3 ms, 在所有 Java 提交中击败了79.79%的用户
内存消耗:36.1 MB, 在所有 Java 提交中击败了65.24%的用户
*/
class Solution {
    public int change(int amount, int[] coins) {
        if(amount==0){
            return 1;
        }
        if(coins.length==0){
            return 0;
        }

        int []dp = new int[amount+1];
        dp[0] = 1;
        for(int j = 0;j<coins.length;j++){
            for(int i = coins[j];i<=amount; i++){
                dp[i] = dp[i]+dp[i-coins[j]];
            }
        }
        return dp[amount];
    }
}
3.不同路径(62):求计数问题

一:确定状态:
	)1:最终状态:机器人在(m-1,n-1)的位置,那他的前一步一定在(m-1,n-2)或者(m-2,n-1)2:子问题:分别求出到达(m-1,n-2)和(m-2,n-1)的方法数,并相加
二:转移方程:f(i,j) = f(i-1,j)+f(i,j-1)
三:初始条件和边界条件:f(00= 1 到原地有一种方式,即机器人不动即可
     由于机器人只能往下走或者往右走,所以f(0,k)= 1 and f(k,0= 1 
四:计算顺序:从上到下,从左到右


/*
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:35.4 MB, 在所有 Java 提交中击败了54.32%的用户
*/
class Solution {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        dp[0][0] = 1;
        for(int i = 0;i<m; i++){
            dp[i][0] = 1;
        }
        for(int j = 0; j<n;j++){
            dp[0][j] = 1;
        }
        for(int i = 1;i<m;i++){
            for(int j = 1;j<n;j++){
                dp[i][j] = dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
}
4.跳跃游戏(55):求存在性问题

一:确定状态:
	)1:最终状态:青蛙到达最后的地方n,则青蛙首先能到达k,并且k+ak>=n
	)2:子问题:青蛙是否能够到达k
二:转移方程:f(i) = f(j)&&(j+aj>=i)  --(i>j)
三:初始条件和边界条件:f(0)=true,肯定能够到达原地
四:计算顺序:从下到上


/*
执行用时:416 ms, 在所有 Java 提交中击败了8.81%的用户
内存消耗:40.5 MB, 在所有 Java 提交中击败了55.36%的用户
*/
class Solution {
    public boolean canJump(int[] nums) {
        boolean[] dp = new boolean[nums.length];
        dp[0]=true;
        for(int i = 1 ;i<nums.length;i++){
            for(int j = 0;j<i;j++){    
                if(dp[j]&&(j+nums[j])>=i){
                    dp[i] = true;
                    break;
                }
            }
        }
         return dp[nums.length-1];
    }
}
5.不同路径 II(63):计数问题


和问题3差不多,只是多了一些对于初始条件的分析:首先当数组a[i,j]=1时,dp[i,j]=0,也就是说当前地方有障碍时,到达该地方的方法数为0

/*
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:37.8 MB, 在所有 Java 提交中击败了40.16%的用户
*/
class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        int [][]dp = new int[m][n];
        //对原点进行判断,当原点有障碍或终点有障碍时,直接返回0
        if(obstacleGrid[0][0]==1||obstacleGrid[m-1][n-1]==1){
           return 0;
        }else{
            dp[0][0] = 1;
        }
        
        //对第一列进行赋值,当有一个点存在障碍时,后面的点都不能到达,不进行赋值,即为0
        for(int i = 1;i<m;i++){
            if(obstacleGrid[i][0]!=1){
                dp[i][0] = 1;
            }else{
               break;
            }
        }

        //同上
        for(int j = 1;j<n;j++){
            if(obstacleGrid[0][j]!=1){
                dp[0][j] = 1;
            }else{
                break;
            }
        }
        
        //f(i,j) = f(i-1,j)+f(i,j-1)
        for(int i = 1;i<m;i++){
            for(int j = 1; j< n ; j++){
                if(obstacleGrid[i][j]==1) continue;
                dp[i][j] = dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
}
6.粉刷房子(256):求最小值
/*
	无会员,无运行结果。
*/
class Solution {
public int minCost(int[][] costs) {
        if(costs==null||costs.length==0){
            return 0;
        }
        int len = costs.length;
        int [][]dp = new int[len+1][3];
        dp[0][0] = 0;
        dp[0][1] = 0;
        dp[0][2] = 0;
    
        for(int i = 1;i<=len;i++){
            for(int j = 0;j<3;j++){
                dp[i][0] = Math.min(dp[i-1][1]+costs[i-1][0],dp[i-1][2]+costs[i-1][1]);
                dp[i][1] = Math.min(dp[i-1][0]+costs[i-1][1],dp[i-1][2]+costs[i-1][2]);
                dp[i][2] = Math.min(dp[i-1][0]+costs[i-1][1],dp[i-1][0]+costs[i-1][2]);
            }
        }

        return Math.min(dp[len][0],dp[len][1],dp[len][2]);
   }
}
7.解码方法(91:求计数

    
一:确定状态:
	)1:最终状态:长度为n的字符串的可解码次数,等于n-1,n-2的解码次数之和,但是要注意S[n-1]要能够组成一个英文字母,s[n-2]s[n-1]能够组成一个英文字母。
	)2:子问题:要想求n解码的次数,转化成求n-1,n-2的解码次数之和
二:转移方程:dp[n] = dp[n-1](S[n-1]要能够组成一个英文字母)+p[n-2](s[n-2]s[n-1]能够组成一个英文字母)
三:初始条件和边界条件:dp[0]=1,当不需要解码时,解出来为空。
四:计算顺序:从下到上
        
/*
执行用时:1 ms, 在所有 Java 提交中击败了99.96%的用户
内存消耗:36.8 MB, 在所有 Java 提交中击败了67.84%的用户
*/
class Solution {
    public int numDecodings(String s) {
        if(s==null||s.length()==0){
            return 1;
        }
        int[] dp = new int[s.length()+1];
        
        //当不输入字符时,即只有一种解码方式,空白
        dp[0]=1;
        
        for(int i = 1;i<=s.length();i++){
           dp[i] = 0;
           int m = s.charAt(i-1)-'0';
            //判断最后一位数字是否能够构成一个英文字母
           if(m>=1&&m<=9){
               dp[i] += dp[i-1];
           }
            
           if(i>=2){
               //判断最后两个数字是否能构成英文字母
               int n = (s.charAt(i-2)-'0')*10+s.charAt(i-1)-'0';
               if(n<=26&&n>=10){
                   dp[i] += dp[i-2];
               }
           }
        }
        return dp[s.length()];
    }
} 
8.最长上升子序列(300:求计数

/*
执行用时:85 ms, 在所有 Java 提交中击败了5.47%的用户
内存消耗:38.3 MB, 在所有 Java 提交中击败了5.02%的用户
*/
class Solution {
    public int lengthOfLIS(int[] nums) {
        if(nums==null||nums.length==0){
            return 0;
        }
        if(nums.length==1) return 1;
        int []dp = new int[nums.length];
        Arrays.fill(dp,1);
        int maxLength = 0;
        for(int i = 1;i<nums.length;i++){
            for(int j = 0;j<i;j++){
                if(nums[i]>nums[j]){
                    dp[i] = Math.max(dp[j]+1,dp[i]);
            }
            if(dp[i]>maxLength){
                maxLength = dp[i];
            }

        }
           
        }
        return maxLength;
    }
}
9.最小路径和(64):求最小值

/*
执行用时:3 ms, 在所有 Java 提交中击败了86.73%的用户
内存消耗:41.4 MB, 在所有 Java 提交中击败了44.82%的用户
*/


class Solution {
    public int minPathSum(int[][] grid) {
        if(grid==null||grid.length==0){
            return 0;
        }
        int m  = grid.length;
        int n = grid[0].length;
        int[][] dp = new int[m][n];
        dp[0][0] = grid[0][0];
        
        //初始化dp数组
        for(int i  = 1;i< m; i++){
            dp[i][0] = dp[i-1][0] + grid[i][0];
        }
        for(int j = 1;j<n;j++){
            dp[0][j] = dp[0][j-1] + grid[0][j];
        }

        //从上方和左方选取较小值
        for(int i = 1;i<m;i++){
            for(int j= 1;j<n;j++){
                dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1])+grid[i][j];
            }
        }

        return dp[m-1][n-1];
    }
}
10.Bomb enemy
        
/*
无会员,无法检验对错。
分成4个方向(上下左右)依次求值。
*/
    
class Solution {
    public int[] maxKilledEnemies(char[][] grid) {
        if(grid==null||grid.length==0||grid[0].length==0){
            return 0;
        }
        int m = grid.length;
        int n = grid[0].length;
        int [][] res = new int[m][n];
        int [][] temp = new int[m][n];
        // 初始化 res
        for(int i = 0;i< m;i++){
            for(int j = 0;j<n;j++){
                res[i][j] = 0 ;
            }
        }

        //up
        for(int i = 0;i<m;i++){
            for(int j = 0;j<n;j++){
                if(grid[i][j] == 'w'){
                    temp[i][j] = 0;
                }else{
                    temp[i][j] = 0;
                    if(grid[i][j]=='E'){
                        temp[i][j] = 1;
                    }
                    if(i>0){
                        temp[i][j] = temp[i-1][j];
                    }
                }
                res[i][j]+=temp[i][j];
            }
        }

        //down
        for(int i = m-1;i>=0;i--){
            for(int j = 0;j<n;j++){
                if(grid[i][j] == 'w'){
                    temp[i][j] = 0;
                }else{
                    temp[i][j] = 0;
                    if(grid[i][j]=='E'){
                        temp[i][j] = 1;
                    }
                    if(i+1<m){
                        temp[i][j] = temp[i+1][j];
                    }
                }
                res[i][j]+=temp[i][j];
            }
        }

        //left
        for(int i = 0;i<m;i++){
            for(int j = 0;j<n;j++){
                if(grid[i][j] == 'w'){
                    temp[i][j] = 0;
                }else{
                    temp[i][j] = 0;
                    if(grid[i][j]=='E'){
                        temp[i][j] = 1;
                    }
                    if(j>0){
                        temp[i][j] = temp[i][j-1];
                    }
                }
                res[i][j]+=temp[i][j];
            }
        }

        //right
        for(int i = 0;i<m;i++){
            for(int j = n-1;j>=0;j--){
                if(grid[i][j] == 'w'){
                    temp[i][j] = 0;
                }else{
                    temp[i][j] = 0;
                    if(grid[i][j]=='E'){
                        temp[i][j] = 1;
                    }
                    if(j+1<n){
                        temp[i][j] = temp[i][j+1];
                    }
                }
                res[i][j]+=temp[i][j];
            }
        }

        //遍历寻找答案
        int ans  = 0
        for(int i = 0;i< m;i++){
            for(int j = 0;j<n;j++){
                if(grid[i][j]=='0'){
                    if(res[i][j]>ans){
                        ans = res[i][j];
                    }
                }
            }
        }

    return ans;    

    }
}
11.比特位计数(338):求计数

/*
执行用时:1 ms, 在所有 Java 提交中击败了99.98%的用户
内存消耗:42.6 MB, 在所有 Java 提交中击败了53.72%的用户
*/
class Solution {
    public int[] countBits(int num) {
        int []dp = new int[num+1];
   
        dp[0] = 0;
        //dp[i/2]:判断i右移一位之后有几个1; i%2:判断i的最后一位是否是1
        for(int i = 0;i<=num;i++){
            dp[i] = dp[i/2] + i%2;
        }
        return dp;
    }
}
12.paint house

class Solution {
public int minCost(int[][] costs) {
        if(costs==null||costs.length==0){
            return 0;
        }
        int len = costs.length;
        int colors = costs[0].length;
        int [][]dp = new int[len+1][colors];

        int min, min2;
        int minNumber=0, min2Number=0;

        //初始条件
        for(int j = 0; j<colors;j++ ){
            dp[0][j] = 0;
        }

        for(int i = 1;i<=len;i++){

             min = min2= Integer.MAX_VALUE;

            //取出dp[i-1][k]的最小值和此小值,并记录位置
            for(int j = 0;j<colors;j++){
                if(dp[i-1][j]<min){
                    min2 = min;
                    min2Number = minNumber;
                    min = dp[i-1][j];
                    minNumber = j;
                }else{
                    if(dp[i-1][j]<min2){
                        min2 = dp[i-1][j];
                        min2Number = j;
                    }
                }
               
            }

            //状态转移方程:dp[i][j] = min{dp[i-1][z]}+cost[i-1][j](z!=j)
            for(int j = 0;j<colors;j++){
                if(j!=minNumber){
                    dp[i][j] = d[i-1][minNumber] + costs[i-1][j];
                }else{
                    dp[i][j] = dp[i-1][min2Number] + costs[i-1][j];
                }
            }
        }

    	// 循环判断,对于最后一栋房子涂什么颜色,会令总花费最小
        int res = Integer.MAX_VALUE;
        for(int i = 0;i<colors;i++){
            if(dp[len][i]<res){
                res = dp[len][i];
            }
        }

        return res;
   }
}
13.打家劫舍(198)
    
    
一:确定状态:
	)1:最终状态:最后一间房子n偷还是不偷,偷的话n-1不能偷,就等于给n-2套房子选择+第n套房子中的财产;不偷就等于给n-1套房子进行选择
	)2:子问题:i偷不偷,i偷,f(i-2+nums[n-1];i不偷,f(i-1)
二:转移方程:f(i) = max(f(i-2)+num[i-1], f(i-1))
三:初始条件和边界条件:f(0) = 0, f(1) = nums[0], f(2) = max(nums[0],nums[1])
四:计算顺序:从下到上

/*
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:35.8 MB, 在所有 Java 提交中击败了77.75%的用户
*/

class Solution {
    public int rob(int[] nums) {
        if(nums==null||nums.length==0){
            return 0;
        }
        int len = nums.length;
        int []dp = new int [len+1];
        dp[0] = 0;
        for(int i = 1;i<= len;i++){
            if(i==1){
                dp[i] = nums[0];
            }else if(i==2){
                dp[i] = Math.max(nums[0],nums[1]);
            }else{
                dp[i] = Math.max(dp[i-1],dp[i-2]+nums[i-1]);
            }
            
        }
        return dp[len];

    }
}
14.打家劫舍Ⅱ(213)

    
分析:从最后一栋房子n开始,由于房子是环形摆放的,所以当最后一栋房子n在选择范围内时,第一栋房子和第n-1栋房子不能被选择,我们可以直接将第一栋房子舍去,[1,n]序号的房子就成了一排;同理当第一栋房子在选择范围内时,第n栋房子和第2栋房子不能被选择,[0,n-1]序号的房子就成了一排。
    从而就变成了上面的那道题。
    
    
/*
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:36.1 MB, 在所有 Java 提交中击败了46.72%的用户	
*/

class Solution {
    public int rob(int[] nums) {
        if(nums==null||nums.length==0){
            return 0;
        }
        if(nums.length==1){
            return nums[0];
        }
        int len = nums.length;
        //当第一栋房子在选择目标内时
        int ans = onlyOne(nums,0,len-1);

        //当最后一栋房子在选择目标内时
        int ans2 = onlyOne(nums,1,len);

        //返回取值大的一种选择
        return ans>ans2?ans:ans2;
    }

    public int onlyOne(int[] nums, int begin, int end){
        //将选择的好的房子重新放置到一个新的数组
        int[] copy = Arrays.copyOfRange(nums,begin,end);
        
        int[] dp = new int[copy.length+1];

        //初始化dp
        dp[0] = 0;
        for(int i = 1;i<=copy.length;i++){
            if(i==1){
                dp[i] = copy[0];
            }else if(i==2){
                dp[i] = Math.max(copy[0],copy[1]);
            }else{
                //状态转移方程
                dp[i] = Math.max(dp[i-1],dp[i-2]+copy[i-1]);
            }
        }
        return dp[copy.length];

    }
}
15.买卖股票的最佳时机&&股票的最大利润(121:买卖一次

/*
执行用时:1 ms, 在所有 Java 提交中击败了98.55%的用户
内存消耗:38.4 MB, 在所有 Java 提交中击败了61.99%的用户
*/
class Solution {
    public int maxProfit(int[] prices) {
        if(prices==null||prices.length==0){
            return 0;
        }
        int len = prices.length;
        int minprice = Integer.MAX_VALUE;
        int maxValue = Integer.MIN_VALUE;
        for(int i = 0;i<len;i++){
            //一直保存股票的最低价
            if(prices[i]<minprice){
                minprice = prices[i];
            }
       		//不断更新股票的最大利润
            int temp = prices[i]-minprice;
            if(temp>maxValue){
                maxValue = temp;
            }
        }
        return maxValue;
    }
}
16.买卖股票的最佳时机(122):买卖多次
    
    
/*
执行用时:1 ms, 在所有 Java 提交中击败了99.32%的用户
内存消耗:38.3 MB, 在所有 Java 提交中击败了68.57%的用户
*/
//把所有上升阶段的利益全部吃到,即为利益最大
class Solution {
    public int maxProfit(int[] prices) {
        int res = 0;
        for(int i = 0;i<prices.length-1;i++){
            
            if(prices[i+1]>prices[i]){
                res += prices[i+1]-prices[i];
            }
        }
        return res;
    }
}




/*
执行用时:4 ms, 在所有 Java 提交中击败了16.06%的用户
内存消耗:38.1 MB, 在所有 Java 提交中击败了92.30%的用户
*/

class Solution {
    public int maxProfit(int[] prices) {
        int [][]dp = new int[prices.length+1][2];
        //初始化条件
        dp[0][0] = 0;dp[0][1] = -prices[0];
        for(int i = 1;i<=prices.length;i++){
            //dp[i][0]:第i天并未拥有股票-->第i-1天也并没有拥有 or 第i-1天拥有,第i天卖了
            dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i-1]);
            
            //dp[i][1]:第i天拥有股票-->第i-1天也拥有 or 第i-1天并未拥有,第i天买了
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]-prices[i-1]);
        }
        //最后的结果,第n天未拥有股票
        return dp[prices.length][0];
    }
}
17.买卖股票的最佳时机(123):买卖两次,这时就需要记录买卖的次数


/*
执行用时:95 ms, 在所有 Java 提交中击败了38.89%的用户
内存消耗:58 MB, 在所有 Java 提交中击败了35.73%的用户
*/

class Solution {
    public int maxProfit(int[] prices) {
        //  dp[i][2][3]:i-天、 2-股票拥有与否 、 3-买卖次数(买卖算一次),这里设置买的时候才会扣次数
        int[][][] dp = new int[prices.length+1][2][3];
        
        // 初始化
        for(int i = 1;i<3;i++){
            dp[0][0][i] = 0;
            dp[0][1][i] = Integer.MIN_VALUE;
        }
        
        for(int i = 1;i<=prices.length;i++){
            for(int j=2;j>=1;j--){
                //状态转移方程
                
                //第i天未拥有股票 = max{第i-1天未拥有股票,第i-1天拥有股票并且第i天卖了}
                dp[i][0][j] = Math.max(dp[i-1][0][j],dp[i-1][1][j]+prices[i-1]);
                
                 //第i天拥有股票 = max{第i-1天拥有股票,第i-1天未拥有股票并且第i天买了}
                dp[i][1][j] = Math.max(dp[i-1][1][j],dp[i-1][0][j-1]-prices[i-1]);
            }
        }
        
        return dp[prices.length][0][2];

    }
}


/*
执行用时:38 ms, 在所有 Java 提交中击败了43.50%的用户
内存消耗:51.5 MB, 在所有 Java 提交中击败了87.37%的用户
*/
class Solution {
    public int maxProfit(int[] prices) {
        if(prices==null||prices.length==0){
            return 0;
        }
        int len = prices.length;
        int [][]dp = new int[len+1][6];
        //初始条件
        dp[0][1] = 0;
        dp[0][2]= dp[0][3] = dp[0][4] = dp[0][5] = Integer.MIN_VALUE;
        
        for(int i = 1;i<=len;i++){
            for(int j = 1;j<=5;j++){
                
                //处于阶段1,3,5
                if(j%2==1&&j>1&&i>=2){
                    dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-1]+prices[i-1]-prices[i-2]);
                }
                
            	//处于阶段2.4
                if(j%2==0&&i-2>=0){
                    dp[i][j] = Math.max(dp[i-1][j]+prices[i-1]-prices[i-2],
                    Math.max(dp[i-1][j-1],dp[i-1][j-2]+prices[i-1]-prices[i-2]));
                }
            }
        }
        return dp[len][5];
    }
}
18.买卖股票的最佳时机 IV(188):买卖k次

    
/*
执行用时:7 ms, 在所有 Java 提交中击败了60.11%的用户
内存消耗:37.6 MB, 在所有 Java 提交中击败了83.93%的用户
*/   
class Solution {
public int maxProfit(int k, int[] prices) {
        if(k>prices.length/2){
            int ans  = 0;
            for(int i= 1;i<prices.length;i++){
                if(prices[i]>prices[i-1]){
                    ans+=prices[i]-prices[i-1];
                }
            }
            return ans;
        }
       int [][][]dp = new int[prices.length+1][2][k+1];
       for(int i =1;i<k+1;i++){
           dp[0][0][i] = 0;
           dp[0][1][i] = Integer.MIN_VALUE;
       }

       for(int i=1;i<prices.length+1;i++){
           for(int j=k;j>=1;j--){
               dp[i][0][j]=Math.max(dp[i-1][0][j],dp[i-1][1][j]+prices[i-1]);
               dp[i][1][j]=Math.max(dp[i-1][1][j],dp[i-1][0][j-1]-prices[i-1]);
           }
       }
    return dp[prices.length][0][k];
    }
}  



/*
执行用时:
3 ms, 在所有 Java 提交中击败了96.33%的用户
内存消耗:37.8 MB, 在所有 Java 提交中击败了82.50%的用户
*/
class Solution {
    public int maxProfit(int k, int[] prices) {
        if(prices==null||prices.length==0){
            return 0;
        }
        int len = prices.length;
        int [][]dp = new int[len+1][2*k+1+1];
        //初始条件
        dp[0][1] = 0;
        for(int i = 2;i<=2*k+1;i++){
            dp[0][i] = Integer.MIN_VALUE;
        }

        
        for(int i = 1;i<=len;i++){
            for(int j = 1;j<=2*k+1;j++){
                
                //处于阶段1,3,5
                if(j%2==1&&j>1&&i>=2){
                    dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-1]+prices[i-1]-prices[i-2]);
                }
                
            	//处于阶段2.4
                if(j%2==0&&i-2>=0){
                    dp[i][j] = Math.max(dp[i-1][j]+prices[i-1]-prices[i-2],
                    Math.max(dp[i-1][j-1],dp[i-1][j-2]+prices[i-1]-prices[i-2]));
                }
            }
        }
        return dp[len][2*k+1];
    }
}
19.最佳买卖股票时机含冷冻期(309/*
执行用时:1 ms, 在所有 Java 提交中击败了99.38%的用户
内存消耗:37.7 MB, 在所有 Java 提交中击败了47.60%的用户
*/

class Solution {
    public int maxProfit(int[] prices) {
    int[][] ans = new int[prices.length+1][2];
    ans[0][1] = Integer.MIN_VALUE;
    ans[0][0] = 0;
    for (int i =1;i<prices.length+1;i++){
        //卖出之后,有一天冷静期才能买入
        //冷静期对第一天无效
        if (i-2<0){
            ans[i][0] = Math.max(ans[i-1][0],ans[i-1][1]+prices[i-1]);
            ans[i][1] = Math.max(ans[i-1][1],-prices[i-1]);
        }else{
            ans[i][0] = Math.max(ans[i-1][0],ans[i-1][1]+prices[i-1]);
            ans[i][1] = Math.max(ans[i-1][1],ans[i-2][0]-prices[i-1]);
        }

    }
    return ans[prices.length][0];
    }
}
20.买卖股票的最佳时机含手续费(714/*
执行用时:5 ms, 在所有 Java 提交中击败了64.88%的用户
内存消耗:47.7 MB, 在所有 Java 提交中击败了61.75%的用户
*/

class Solution {
    public int maxProfit(int[] prices, int fee) {
        if(prices==null||prices.length==0){
            return 0;
        }
        int dp_i_1 = Integer.MIN_VALUE;
        int dp_i_0 = 0;
        for(int i = 1;i<prices.length+1;i++){
            dp_i_0 = Math.max(dp_i_0,dp_i_1+prices[i-1]);
            dp_i_1 = Math.max(dp_i_1,dp_i_0-prices[i-1]-fee);
        }
        return dp_i_0;
    }
}
21.俄罗斯套娃信封问题(354/*
执行用时:301 ms, 在所有 Java 提交中击败了21.89%的用户
内存消耗:39.6 MB, 在所有 Java 提交中击败了48.79%的用户
*/
class Solution {
    public int maxEnvelopes(int[][] envelopes) {
        if(envelopes==null||envelopes.length==0){
            return 0;
        }
        //先对信封进行排序
        Arrays.sort(envelopes,(a,b)->(a[0]!=b[0]?a[0]-b[0]:a[1]-b[1]));
        int n = envelopes.length;
        int[] dp = new int[n];
        int res = 0;
        for(int i = 0;i<n;i++){
            // 初始化dp数组,每个信封都可以装他自己,即为1
            dp[i] = 1;
            for(int j = 0;j<i;j++){
                //一定要注意条件,长宽都比另一个信封大的时候才能装进去
                if(envelopes[i][0]>envelopes[j][0]&&envelopes[i][1]>envelopes[j][1]){
                    dp[i] = Math.max(dp[i],dp[j]+1);
                }
            }
            res = Math.max(res,dp[i]);
        }
        return res;
    }
}


22.完全平方数(279/*
执行用时:41 ms, 在所有 Java 提交中击败了75.85%的用户
内存消耗:37.7 MB, 在所有 Java 提交中击败了69.40%的用户
*/
class Solution {
    public int numSquares(int n) {
        int[] dp = new int[n+1];
        //这里不要设置Integer.MAX_VALUE,可设置的范围[n,Integer.MAX_VALUE)
        Arrays.fill(dp,n);
        
        //初始条件
        dp[0]=0;
        for(int i = 1;i<=n;i++){
            for(int j = 1;j*j<=i;j++){
                if(i-j*j>=0){
                     dp[i] = Math.min(dp[i],dp[i-j*j]+1);
                }
               
            }
        }
        return dp[n];
    } 
}
23.分割回文串 II(132/*
执行用时:1165 ms, 在所有 Java 提交中击败了22.03%的用户
内存消耗:38.5 MB, 在所有 Java 提交中击败了50.40%
的用户
*/
class Solution {
    public int minCut(String s) {
        if(s==null||s.length()==0){
            return 0;
        }
        int[] dp = new int[s.length()+1];
        dp[0] = 0;
        for(int i = 1;i< s.length()+1;i++){
            dp[i] = Integer.MAX_VALUE;
            for(int j =0;j<i;j++){
                if(judge(s.substring(j,i))){
                    dp[i] = Math.min(dp[i],dp[j]+1);
                    
                 }
            }
        }
        //题目问的是最少划分几次,而求得的是dp[i]:i最少可以划分成几个回文串
        return dp[s.length()]-1;
    }
    
    //判断所传入的字符串是否为回文数
    public boolean judge(String temp){
        int len = temp.length();
        if(len==1){
            return true;
        }
        for(int i = 0;i<len/2;i++){
            if(temp.charAt(i)!=temp.charAt(len-i-1)){
                return false;
            }
        }
        return true;
    }
}
24.copy books
25.Coins in a Line:博弈型动态规划

题目:
)1.有一排N个石子,A、B两人轮流取石子
)2.每次一个人从最右边取走1个或者2个石子
)3.取走最后石子的人胜利
)4.问A先手是否必胜

例:N=5 true

public boolean firstWillWin(int n){
	if(n==0) return false;
	boolean[] dp = new int[n+1];
    // 当只有1个和2个石子的时候,必胜。
	dp[1] = true;
	dp[2] = true;
    //dp[i]:面对i个石子,是否先手会胜
	for(int i = 3;i<=n;i++){
        //i为A走,则i-1 or i-2是对手B走。
		dp[i] = !dp[i-1]||!dp[i-2];
	}
	return dp[n];
}
26.背包DP{
    1.最大承重问题 and 恰好取到背包容量--可行性问题
    2.承重组合数(每个Ai只能用一次)(每个Ai可用多次)--计数问题
    3.最大价值(每个Ai只能用一次)(每个Ai可用多次)--最值问题    
}1.最大承重问题 and 恰好取到背包容量
    
最大承重问题:给定N个物品,重量分别是A0,A1,...,An-1;一个背包的最大容量为M;问最多能带走多重的物品
例:in:[2,3,5,7];M=11
   out:10
            
public int backPack(int M, int[] A){
		if(A==null||A.length==0){
        	return null;
		}
                
        int len = A.length;
        int[][] dp = new int[len+1][W+1];
        //初始化数组
        dp[0][0]=true;
        for(int i = 1;i<=len;i++){
            dp[i][0] = false;
        }
        
        for(int i=1;i<=len;i++){
            for(int j =0;j<=W;j++){
                dp[i][j] = dp[i-1][j];
                if(j-A[i-1]>=0){
                    dp[i][j] = dp[i-1][j]||dp[i-1][j-A[i-1]];
                }
            }
        }
        //依次往下遍历,找到一个可以填满的即为最大!        
        for(int i = W;i>=0;i--){
            if(dp[len][i]){
                return i;
            }
        }
}


恰好取到背包容量:分割等和子集(416)
/*
执行用时:50 ms, 在所有 Java 提交中击败了31.25%的用户
内存消耗:39 MB, 在所有 Java 提交中击败了52.75%的用户
*/
class Solution {
    public boolean canPartition(int[] nums) {
       if(nums==null||nums.length==0){
           return false;
       }
       int  sum = 0;
       for(int i:nums){
           sum+=i;
       }
       //当数据集的总和为奇数时,不可能等分
       if(sum%2==1) return false;
       
       //判断前n个是否能够分出sum/2的元素和
       boolean[][] dp = new boolean[nums.length+1][sum/2+1];
        
       //初始条件
       dp[0][0] = true;
       for(int i = 1;i<nums.length+1;i++){
           for(int j = 0;j<sum/2+1;j++){
               //dp[i-1][j]:前i-1个是否能够得到j元素和
               //dp[i-1][j-nums[i-1]]:前i-1是否能够得到j-nums[i-1]元素和
               if(j-nums[i-1]>=0){
                   dp[i][j] = dp[i-1][j]||dp[i-1][j-nums[i-1]];
               }else{
                    dp[i][j] = dp[i-1][j];
               }
           }
       }
       return dp[nums.length][sum/2];
   } 
}2.承重组合数(每个Ai只能用一次)(每个Ai可用多次)
    
 	(每个Ai只能用一次)
     题意:给定N个正整数,A0,A1,...,An-1;一个正整数Target;求有多少种组合加起来是target;每个Ai只能用一次
    in:A=[1,2,3,3,7] Target=7
    out:2(7=7,1+3+3=7)
class Solution {
    public int backPack(int[] nums,int Target) {
      if(nums==null||nums.length==0){
          return null;
      }
      int len = nums.length;
      int[][] dp = new int[len+1][Target+1];
      dp[0][0] = 1;
      for(int i=1;i<=Target;i++){
          dp[0][i]=0;
      }
     for(int i = 1;i<=len;i++){
         for(int j = 1;j<=Target;j++){
             if(j-nums[i-1]>=0){
                 dp[i][j] = dp[i][j]+dp[i-1][j-nums[i-1]];
             }
         }
     } 
    return dp[len][Target];
}
    
    
    
   (每个Ai可用多次)
    题意:给定N个正整数,A0,A1,...,An-1;一个正整数Target;求有多少种组合加起来是target;每个Ai可用多次
class Solution {
    public int backPack(int[] nums,int Target) {
      if(Target==0){
            return 1;
        }
      if(nums==null||nums.length==0){
          return null;
      }
      int len = nums.length;
      int[] dp = new int[Target+1];
      dp[0] = 1;
     
     for(int i = 1;i<=len;i++){
         for(int j = 1;j<=Target;j++){
             if(j-nums[i-1]>=0){
                 dp[j] = dp[j]+dp[j-nums[i-1]];
             }
         }
     } 
    return dp[Target];
}3.最大价值(每个Ai只能用一次)(每个Ai可用多次)
    
   (每个Ai只能用一次)
  题意:给定N个正整数,A0,A1,...,An-1;价值分别为正整数V0,V1,...,Vn-1;最大承重量M;求最多能带走多大价值的物品
  in:weigth[2,3,5,7];value[1,5,2,4];W=11
  out:9
      
(二维数组版)  
class Solution {
    public int backPack(int m, int[] nums,int[] values) {
      if(nums==null||nums.length==0){
          return null;
      }
      int len = nums.length;
      int[][] dp = new int[len+1][m+1];
      //初始化条件
      dp[0][0] = 0;
      for(int i = 1;i<=m;i++){
          dp[0][i] = -1;
      }
     
      for(int i = 1;i<=len;i++){
          for(int j = 0;j<=m;j++){
              dp[i][j] = dp[i-1][j];
              if(j-nums[i-1]>=0&&dp[i-1][j-nums[i-1]]!=-1){
                  dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-nums[i-1]]+values[i-1]);
              }
              if(dp[i][j]>max){
                  max = dp[i][j];
              }
          }
      } 
    return max;
}
    

    
(一维数组版)
class Solution {
    public int backPack(int m, int[] nums,int[] values) {
      if(nums==null||nums.length==0){
          return null;
      }
      int len = nums.length;  
      int[] dp = new int[m+1];
      int max = 0;
      //初始化条件
      dp[0] = 0;
      for(int i = 1;i<=m;i++){
          dp[i] = -1;
      }
     
      for(int i = 1;i<=len;i++){
          for(int j = m;j>=0;j--){
          		if(j-A[i-1]>=0&&dp[j-A[i-1]]!=-1){
                    f[j] = Math.max(f[j],f[j-A[i-1]]+values[i-1]);
                }
               if(f[j]>max){
                   max = f[j];
               }
              
          }
      } 
    return max;
}    
    
    
    
    (每个Ai可用多次)
     题意:给定N个正整数,A0,A1,...,An-1;价值分别为正整数V0,V1,...,Vn-1;最大承重量M;每种物品都有无穷多个。求最多能带走多大价值的物品
  in:weigth[2,3,5,7];value[1,5,2,4];W=10
  out:153个物品一,w=3*3=9,v=3*5=15(一维数组版)
class Solution {
    public int backPack(int m, int[] nums,int[] values) {
      if(nums==null||nums.length==0){
          return null;
      }
      int len = nums.length;
      int[] dp = new int[m+1];
      int max = 0;
      //初始化条件
      dp[0] = 0;
      for(int i = 1;i<=m;i++){
          dp[i] = -1;
      }
     
      for(int i = 1;i<=len;i++){
          for(int j = 0;j<=m;j++){
          		if(j-A[i-1]>=0&&dp[j-A[i-1]]!=-1){
                    f[j] = Math.max(f[j],f[j-A[i-1]]+values[i-1]);
                }
               if(f[j]>max){
                   max = f[j];
               }
              
          }
      } 
    return max;
}    
27.最长回文子序列(516/*
执行用时:58 ms, 在所有 Java 提交中击败了10.84%的用户
内存消耗:48.7 MB, 在所有 Java 提交中击败了38.44%的用户
*/

class Solution {
    public int longestPalindromeSubseq(String s) {
        int len = s.length();
        if (len==0||s==null) return 0;
        int[][] dp = new int[len][len];

        //初始化数组,当只有一个字符时,回文序列的长度为1
        for (int i = 0;i<len;i++) dp[i][i] = 1;


        //sub:序列[i-j]中字符的个数
        for(int sub=2;sub<=len;sub++){
            for(int i = 0;i<=len-sub;i++){
                int j = i+sub-1;
                //先找出[i+1,j]和[i,j-1]中的最长回文子序列
                dp[i][j] = Math.max(dp[i+1][j],dp[i][j-1]);
                
                //当s[i]==s[j]时
                if(s.charAt(i)==s.charAt(j)){
                    dp[i][j] = Math.max(dp[i+1][j-1]+2,dp[i][j]);
                }
            }
        }
    return dp[0][len-1];
    }
}
28.Coins in a Line(877. 石子游戏)

题目:
)1.给定一个序列a[n]2.A、B两人轮流取石子
)3.每次一个人每次只能取第一个数或者最后一个数
)4.双方都用最优策略,使得自己的数字和尽量比对手大
)5.问先手是否必胜(如何数字和一样,也算先手胜)

in:[1,5,233,7]
out:True(先手取走1,无论后手取哪个,先手都能取走233)

//面向测试用例编程
class Solution {
    public boolean stoneGame(int[] piles) {
       return true; 
    }
}

/*
执行用时:10 ms, 在所有 Java 提交中击败了23.12%的用户
内存消耗:38.9 MB, 在所有 Java 提交中击败了47.25%的用户
*/
class Solution {
    public boolean stoneGame(int[] piles) {
        if(piles==null||piles.length==0){
            return true;
        }
        int len = piles.length;
        int[][] dp = new int[len][len];

        //当该序列中只有一个数字时,两人数字和之差就为该数字
        for(int i = 0;i<len;i++){
            dp[i][i] = piles[i];
        }

        //i:划分序列初始位置值  j:划分序列的终止位置值
        for(int sub = 2;sub<=len;sub++){
            for(int i = 0;i<=len-sub;i++){
                int j = i+sub-1;
                //当取第一件物品时 vs 取最后一件物品
                dp[i][j] = Math.max(piles[i]-dp[i+1][j],piles[j]-dp[i][j-1]);

            }

        }
        return dp[0][len-1]>=0?true:false;
    }
}  
29.扰乱字符串(87)
30.戳气球(312/*
执行用时:92 ms, 在所有 Java 提交中击败了12.64%的用户
内存消耗:37.8 MB, 在所有 Java 提交中击败了21.98%的用户
*/
    
class Solution {
    public int maxCoins(int[] nums) {
        if(nums==null||nums.length==0){
            return 0;
        }
        int len = nums.length;
        
        //定义数组temp,将其0和n+1的位置设置为1,其他位置 temp[i]=nums[i-1]
        int[] temp = new int[len+2];
        temp[0] = 1;
        temp[len+1] = 1;
        for(int i = 1;i<=len;i++){
            temp[i] = nums[i-1];
        }
        
        //定义dp数组,dp[i][j]:扎破i+1一j-1号气球的最多获得的金币数
        int[][] dp = new int[len+2][len+2];
        //初始化dp数组
        for(int i = 0;i<len+1;i++){
            dp[i][i+1] = 0;
        }

        for(int sub = 3;sub<=len+2;sub++){
            //i:区间的左端点     j:区间的右端点
            for(int i=0;i<=len+2-sub;i++){
                int j = i+sub-1;
                dp[i][j] = 0;
                
                //k:选择i+1一j-1中的一个气球作为最后被扎破的对象
                //这时区间[i,j]被分成了[i,k] 和 [k,j]
                //最后k的乘积值:temp[i]*temp[k]*temp[j]
                for(int k = i+1;k<j;k++){
                    dp[i][j] = Math.max(dp[i][j],dp[i][k]+dp[k][j]+temp[i]*temp[k]*temp[j]);
                }
            }
        }
         return dp[0][len+1];
    }   
}
31.最长公共子序列(1143/*
执行用时:17 ms, 在所有 Java 提交中击败了13.68%的用户
内存消耗:41.9 MB, 在所有 Java 提交中击败了85.18%的用户
*/
class Solution {
 public int longestCommonSubsequence(String text1, String text2) {
        int [][] dp = new int[text1.length()+1][text2.length()+1];

     	//初始化数组,空串和任何的序列的公共子序列为0
        for (int i =0;i<text1.length();i++)  dp[i][0] = 0;
        for (int i = 0;i<text2.length();i++) dp[0][i] = 0;

        for (int i = 1;i<=text1.length();i++){
            for (int j = 1;j<=text2.length();j++){

                //当text1和text2中的最后一个字符相等时,则接下来进行判断其它字符
                if (text1.charAt(i-1)==text2.charAt(j-1)) dp[i][j] = 1+dp[i-1][j-1];
                
                //当最后一个字符不相等时,选择舍去text1、text2两个其中一个的最后一个值
                else dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);

            }
        }
        return dp[text1.length()][text2.length()];
    }
}
32.交错字符串(97/*
执行用时:4 ms, 在所有 Java 提交中击败了63.85%的用户
内存消耗:36.3 MB, 在所有 Java 提交中击败了97.42%的用户
*/
class Solution {
    public boolean isInterleave(String s1, String s2, String s3) {
        int len1 = s1.length();
        int len2 = s2.length();
        int len3 = s3.length();

        char[] c1 = s1.toCharArray();
        char[] c2 = s2.toCharArray();
        char[] c3 = s3.toCharArray();

		//当len(s1)+len(s2)!=len(s3)时,肯定不符合条件,返回false
        if(len1+len2!=len3){
            return false;
        }

        boolean[][] dp = new boolean[len1+1][len2+1];
        //初始化数组
        dp[0][0] = true;
        
        for(int i = 0;i<=len1;i++){
            for(int j = 0;j<=len2;j++){
				
                //当c1的最后一个字符和c3最后一个字符相同时,c1长度减一,继续判断[i-1][j],注意这时并不需要j>0.
                if (i>0&&c1[i-1]==c3[i+j-1]){
                    dp[i][j] = dp[i][j]||dp[i-1][j];
                } 
                
                i
                 //当c2的最后一个字符和c3最后一个字符相同时,c2长度减一,继续判断[i][j-1],注意这时并不需要i>0.
                if(j>0&&c2[j-1]==c3[i+j-1]){
                    dp[i][j] = dp[i][j]||dp[i][j-1];
                }
            }
        }
        return dp[len1][len2];
    }
}
33.编辑距离(72/*
执行用时:5 ms, 在所有 Java 提交中击败了95.53%的用户
内存消耗:38.3 MB, 在所有 Java 提交中击败了85.35%的用户
*/
class Solution {
    public int minDistance(String word1, String word2) {
        int len1 = word1.length();
        int len2 = word2.length();

        char[] c1 = word1.toCharArray();
        char[] c2 = word2.toCharArray();

        int[][] dp = new int[len1+1][len2+1];

        for(int i = 0;i<=len1;i++){
            for(int j = 0;j<=len2; j++){
                //当word1和word2中有空串的情况出现
                if(i==0||j==0){
                    // 当word1为空时,只需增加操作
                    if(i==0){
                        dp[i][j] = j;
                    }else{
                    // 当word2为空时,只需删除操作
                        dp[i][j] = i;
                    }
                }else{
                    //dp[i][j-1]+1:word1最后增加word2[n],word2左移一位,操作数加1
                    //dp[i-1][j]+1: word1删除最后一位,word1左移一位,操作数加1
                    //dp[i-1][j-1]+1:word1把最后一位替换成word2[n],两个字符串分别左移一位,操作数加1
                    dp[i][j] = Math.min(dp[i][j-1]+1, Math.min(dp[i-1][j]+1,dp[i-1][j-1]+1));

                    
                    //dp[i-1][j-1]:最后一位相等,两个字符串分别左移一位,操作数无变化。
                     if(c1[i-1]==c2[j-1]){
                        dp[i][j] = Math.min(dp[i-1][j-1],dp[i][j]);
                    }
                }

            }
        }
        return dp[len1][len2];
    }
} 
34.不同的子序列(115/*
执行用时:3 ms, 在所有 Java 提交中击败了94.89%的用户
内存消耗:36.8 MB, 在所有 Java 提交中击败了64.26%的用户
*/
class Solution {
    public int numDistinct(String s, String t) {
        int len1 = s.length();
        int len2 = t.length();

        if(len1<len2){
            return 0;
        }
        char[] c1 = s.toCharArray();
        char[] c2 = t.toCharArray();

        int[][] dp = new int[len1+1][len2+1];

        for(int i = 0;i<=len1;i++){
            for(int j = 0;j<=len2;j++){
                if(i==0||j==0){
                    if(j==0){
                        dp[i][j] = 1;
                    }else{
                        dp[i][j] = 0;
                    }
                    
                }else{
                    dp[i][j] = dp[i-1][j];
                    if(c1[i-1]==c2[j-1]){
                        dp[i][j] = dp[i][j]+dp[i-1][j-1];
                    }
                }
            }
        }
        return dp[len1][len2];
    }
}
35.正则表达式匹配(10/*
执行用时:2 ms, 在所有 Java 提交中击败了99.30%的用户
内存消耗:38.3 MB, 在所有 Java 提交中击败了48.33%的用户
*/
class Solution {
    public boolean isMatch(String s, String p) {

        int len1 = s.length();
        int len2 = p.length();

        char[] c1 = s.toCharArray();
        char[] c2 = p.toCharArray();

        boolean[][] dp = new boolean[len1+1][len2+1];
        
        for(int i = 0;i<=len1;i++){
            for(int j = 0;j<=len2;j++){
                //初始化数组
                if(j==0){
                    if(i==0){
                        //当s和p都为0时,dp[i][j]=true;
                        dp[i][j] = true;
                    }else{
                        //只有当p为0时,dp[i][j]=false;
                        dp[i][j] = false;
                    }
                }else{
                    dp[i][j] = false;
                    //当p[j]为‘.’或者p[j]==s[i],两个字符串均左移
                     if(i>0&&(c2[j-1]=='.'||c2[j-1]==c1[i-1])){
                        dp[i][j] = dp[i-1][j-1];
                         
                    //当p[j]为‘*’时,分为两种情况
                    //    1.p[j-1]p[j]所组成的字符串并不是所需的字符串,因此p[j-1]*表示0个p[i-1],p左移两位
                    //    2.为所需字符串,则s左移一位
                    }else if(c2[j-1]=='*'){
                        dp[i][j] = dp[i][j-2];
                        if(i>0&&j-2>=0&&(c2[j-2]=='.'||c2[j-2]==c1[i-1])){
                            dp[i][j]|=dp[i-1][j];
                        }     
                    }

                }
            }
        }
        return dp[len1][len2];
    }
}
36.通配符匹配(44/*
执行用时:22 ms, 在所有 Java 提交中击败了80.21%的用户
内存消耗:39 MB, 在所有 Java 提交中击败了52.59%的用户
*/
class Solution {
    public boolean isMatch(String s, String p) {
        int len1 = s.length();
        int len2 = p.length();

        char[] c1 = s.toCharArray();
        char[] c2 = p.toCharArray();

        boolean[][] dp = new boolean[len1+1][len2+1];

        for(int i = 0;i<=len1;i++){
            for(int j = 0;j<=len2;j++){
                if(j==0){
                    if(i==0){
                        dp[i][j] = true;
                    }else{
                        dp[i][j] = false;
                    }
                }else{
                    dp[i][j] = false;
                    //当p[j]=s[i] or  p[j]='?'时,p和s左移一位
                    if(i>0&&(c1[i-1]==c2[j-1]||c2[j-1]=='?')){
                        dp[i][j] = dp[i-1][j-1];

                    //当p[j]为‘*’时,分为两种情况
                    //    1.p[j]并不是所需的字符串,所以p左移一位
                    //    2.为所需字符串,则s左移一位   
                    }else if(c2[j-1]=='*'){
                        dp[i][j] = dp[i][j-1];
                        if(i>0){
                            dp[i][j] |= dp[i-1][j];
                        }  
                    }
                }
            }
        }
        return dp[len1][len2];
    }
}
37.一和零(474)
/*
执行用时:359 ms, 在所有 Java 提交中击败了5.01%的用户
内存消耗:67.3 MB, 在所有 Java 提交中击败了19.32%的用户
*/
class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        //类似于背包问题,从最后一个字符串考虑,判断其在不在子集中
        //限制条件,字符串的数目,数字0的个数m,数字1的个数n

        //建立3维数组
        int[][][] dp = new int[strs.length+1][m+1][n+1];


        for(int i = 0;i<=strs.length;i++){
            for(int j = 0;j<=m;j++){
                for(int k = 0;k<=n;k++){
                    //当数组中元素的个数为0时,其最大子集为0
                    if(i==0){
                        dp[i][j][k] = 0;
                    }else{
                        //初始化dp[i][j][k]:不把strs[i]装入子集
                        dp[i][j][k] = dp[i-1][j][k];

                        //获取strs[i]中0和1的个数
                        int len0 = 0, len1 = 0;
                        for(int z = 0;z<strs[i-1].length();z++){
                            if(strs[i-1].charAt(z)=='0'){
                                len0++;
                            }else if(strs[i-1].charAt(z)=='1'){
                                len1++;
                            }
                        }
                        //如果strs[i]中0和1的个数小于规定值,判断装还是不装strs[i]
                        // !!!一定记得装strs[i]时,方法数要加1
                        if(j-len0>=0&&k-len1>=0){
                            dp[i][j][k] = Math.max(dp[i][j][k],dp[i-1][j-len0][k-len1]+1);
                        }
                        
                    }
                }
            }
        }
        return dp[strs.length][m][n];

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值