动态规划题目1


交错字符串

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解题思路:
基本上涉及到字符串匹配的问题都可以用动态规划。
本题我一开始想的是dp[i][j]: s1[0…i]与s2[0…j]的字串能否拼接成s3[0…i+j+1],但是初始化就出现了问题,dp[0][j]和dp[i][0]不好初始化,于是转变思路:
dp[i][j]: s1的前i个字符和s2的前j个字符能否交错拼接成s3[0…i+j-1],然后开辟dp数组 dp[s1.size()+1][s2.size()+1],则可初始化dp[0][0]=true.

class Solution {
public:
    bool DP(string s1, string s2, string s3){
        //dp[i][j]: s1的前i个字符与s2的前j个字符能否交错拼成s3的前i+j个字符
        int n=s1.length();
        int m=s2.length();
        auto dp = vector < vector <int> > (n + 1, vector <int> (m + 1, false));
        dp[0][0]=true;//""+""=""一定能拼成
        for(int c=1;c<=m;++c){
            dp[0][c]=s2.substr(0,c)==s3.substr(0,c);
        }
        for(int r=1;r<=n;++r){
            dp[r][0]=s1.substr(0,r)==s3.substr(0,r);
        }
        for(int i=0;i<=n;++i){
            for(int j=0;j<=m;++j){
                int t=i+j-1;//拼成s3[0...i+j-1]
                if(i>0&&s3[t]==s1[i-1]){
                    dp[i][j]|=dp[i-1][j];
                }
                if(j>0&&s3[t]==s2[j-1]){
                    dp[i][j]|=dp[i][j-1];
                }
            }
        }
        return dp[n][m];
    }
    bool isInterleave(string s1, string s2, string s3) {
        if(s1==""&&s2==""){
            return s3=="";
        }
        if(s1=="")return s3==s2;
        if(s2=="")return s3==s1;
        if(s3=="")return false;
        //s1,s2,s3都不为空串
        if(s1.length()+s2.length()!=s3.length())return false;
        return DP(s1,s2,s3);
    }
};

在这里插入图片描述


打家劫舍

在这里插入图片描述

class Solution {
public:
    int DP(vector<int>& nums){
        int n=nums.size();
        vector<int>dp(n,0);
        //dp[i]: 抢劫0~i最高金额
        dp[0]=nums[0];
        if(n==1)return dp[0];
        dp[1]=max(nums[0],nums[1]);
        for(int i=2;i<n;++i){
            dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
            //dp[i-2]+nums[i]:偷i
            //dp[i-1]:不偷i
        }
        return dp[n-1];
    }
    int rob(vector<int>& nums) {
        return DP(nums);
    }
};

在这里插入图片描述

等差数列划分

在这里插入图片描述

解题思路:

从左到右尝试,

class Solution {
public:
    int DP(vector<int>& nums){
        int res=0;
        vector<int>dp(nums.size(),0);
        for(int i=2;i<nums.size();++i){
            if(nums[i]-nums[i-1]==nums[i-1]-nums[i-2]){
                dp[i]=dp[i-1]+1;
            }
            res+=dp[i];
        }
        return res;
    }
    int numberOfArithmeticSlices(vector<int>& nums) {
        return DP(nums);
    }
};

在这里插入图片描述


解码方法

在这里插入图片描述

在这里插入图片描述

class Solution {
public:
    int DP(string s){
        vector<int>dp(s.length(),0);
        if(s[0]=='0')return 0;
        dp[0]=1;
        if(s.length()==1)return 1;
        stringstream ss;
        ss<<s.substr(0,2);
        int val;
        ss>>val;
        dp[1]=val<10?0:(val>26?(s[1]=='0'?0:1):(s[1]=='0'?1:2));
        for(int i=2;i<s.length();++i){
            dp[i]=s[i]=='0'?0:dp[i-1];
            if(s[i-1]!='0'&&s.substr(i-1,2)<="26"){
                dp[i]+=dp[i-2];
            }
        }
        return dp[s.length()-1];
    }
    int numDecodings(string s) {
        return DP(s);
    }
};

在这里插入图片描述


背包问题

0-1 背包问题

分割等和子集

在这里插入图片描述
具体的解题思路参考:

0-1背包问题详解

class Solution {
public:
    bool DP(int n,int target,vector<int>& nums){
        //0-1背包问题,数字是物品,数值既是物品的重量,又是物品的价值
        //dp[i][j]: 0~i选物品,背包的最大重量是j,最大价值
        int dp[n][target+1];
        for(int i=0;i<n;++i){
            dp[i][0]=0;
        }
        int c=0;
        for(;c<nums[0]&&c<=target;++c){
            dp[0][c]=0;
        }
        for(;c<=target;++c){
            dp[0][c]=nums[0];
        }
        
        for(int i=1;i<n;++i){
            for(int j=1;j<=target;++j){
                dp[i][j]=max((j-nums[i]>=0?dp[i-1][j-nums[i]]+nums[i]:0),dp[i-1][j]);
            }
        }
        // for(int i=0;i<n;++i){
        //     for(int j=0;j<=target;++j){
        //         cout<<dp[i][j]<<" ";
        //     }
        //     cout<<endl;
        // }
        //返回 dp[n-1][target]==target
        return dp[n-1][target]==target;
    }
    bool canPartition(vector<int>& nums) {
        int sum=0;
        for(int i:nums){
            sum+=i;
        }
        if((sum&1)==1){
            return false;
        }
        int target=sum>>1;
        return DP(nums.size(),target,nums);
    }
};

在这里插入图片描述


最后一块石头的重量 II

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    int DP(vector<int>& stones,int target,int sum){
        //dp[i][j]: 从0~i里面选石头,背包最大重量是j,可以获得的最大的价值
        int n=stones.size();
        int dp[n][target+1];
        for(int i=0;i<n;++i){
            dp[i][0]=0;
        }
        int c=0;
        for(;c<stones[0]&&c<=target;++c){
            dp[0][c]=0;
        }
        for(;c<=target;++c){
            dp[0][c]=stones[0];
        }
        for(int i=1;i<n;++i){
            for(int j=1;j<=target;++j){
                dp[i][j]=max(dp[i-1][j],j-stones[i]>=0?dp[i-1][j-stones[i]]+stones[i]:0);
            }
        }
        return (sum-dp[n-1][target])-dp[n-1][target];
    }
    int lastStoneWeightII(vector<int>& stones) {
        //尽量把石头分成重量相等的两份
        int sum=0;
        for(int i:stones){
            sum+=i;
        }
        int target=sum>>1;
        return DP(stones,target,sum);
    }
};

在这里插入图片描述


目标和

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    int DP(int n,int target,vector<int>& nums){
        //0-1背包
        //dp[i][j]: 0~i里面选物品,背包容量是j,恰好装满背包的方法数
        int dp[n][target+1];
        dp[0][0]=nums[0]==0?2:1;
        for(int i=1;i<n;++i){//背包容量是0,装满的方法数,如果有0的话
            dp[i][0]=nums[i]==0?(dp[i-1][0]>>1):dp[i-1][0];
        }
        
        for(int j=1;j<=target;++j){
            if(j==nums[0]){
                dp[0][j]=1;
            }else{
                dp[0][j]=0;
            }
        }
        for(int i=1;i<n;++i){
            for(int j=0;j<=target;++j){
                dp[i][j]=dp[i-1][j]+(j-nums[i]>=0?dp[i-1][j-nums[i]]:0);
            }
        }
        
        // for(int i=0;i<n;++i){
        //     for(int j=0;j<=target;++j){
        //         cout<<dp[i][j]<<" ";
        //     }
        //     cout<<endl;
        // }
        return dp[n-1][target];
    }
    int findTargetSumWays(vector<int>& nums, int target) {
        //假设正数的和为x ,负数绝对值的和为 sum-x, x-(sum-x)=target
        //2x=sum+target
        //x=(sum+target)>>1;
        int sum=0;
        //sum+target奇数返回0
        for(int i:nums){
            sum+=i;
        }
        if(((sum+target)&1)==1||sum+target<0)return 0;
        int x=(sum+target)>>1;
        return DP(nums.size(),x,nums);
    }
};

在这里插入图片描述


一和零

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    int DP(vector<string>& strs,int m,int n){
        int dp[m+1][n+1];
        for(int i=0;i<=m;++i){
            for(int j=0;j<=n;++j){
                dp[i][j]=0;
            }
        }
        for(string str:strs){
            int cnt0=0;
            int cnt1=0;
            for(char c:str){
                if(c=='0')cnt0++;
                else cnt1++;
            }
            for(int i=m;i>=cnt0;--i){
                for(int j=n;j>=cnt1;--j){
                    dp[i][j]=max(dp[i-cnt0][j-cnt1]+1,dp[i][j]);
                }
            }
        }
        return dp[m][n];

    }
    int findMaxForm(vector<string>& strs, int m, int n) {

        return DP(strs,m,n);
    }
};

在这里插入图片描述


完全背包问题


整数拆分

在这里插入图片描述

class Solution {
public:
    int DP(int n){
        //完全背包问题
        //背包是容量是n,物品体积就是拆分的数,乘积最大化就是价值最大化
        //dp[i] :将容量为i的背包装满
        vector<int>dp(n+1,0);
        if(n==2)return 1;
        dp[1]=1;
        dp[2]=1;
        for(int i=3;i<=n;++i){
            //dp[i]最大价值
            for(int j=i-1;j>=1;--j){
                dp[i]=max(j*max(i-j,dp[i-j]),dp[i]);
            }
        }
        return dp[n];
    }
    int integerBreak(int n) {
        return DP(n);
    }
};

在这里插入图片描述


单词拆分

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    unordered_set<string>set;
    bool DP(string s, vector<string>& words){
        int n=s.length();
        int m=words.size();
        vector<bool>dp(n+1,false);
        //dp[i]: s的前i个字符组成的字串能否由字典里的单词拼接成
        dp[0]=true;//容量为0的背包总可以恰好装满
        for(int i=1;i<=n;++i){//i是背包
            for(int j=0;j<i;++j){
                string w=s.substr(j,i-j);
                if(set.find(w)!=set.end()&&dp[j]){//容量为j恰好装满&&剩下的空间刚好可以被一件物品装满
                    dp[i]=true;break;
                }
            }
        }
        return dp[n];
    }
    bool wordBreak(string s, vector<string>& wordDict) {
        for(string s:wordDict){
            set.insert(s);
        }
        return DP(s,wordDict);
    }
};

在这里插入图片描述


零钱兑换 II

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    int DP(vector<int>& coins,int amount){
        int n=coins.size();
        //dp[i][j]: 从0~i中选硬币,恰好凑成j
        int dp[n][amount+1];
        for(int i=0;i<n;++i){
            for(int j=0;j<=amount;++j){
                dp[i][j]=0;
            }

        }
        for(int j=0;j<=amount;++j){
            if(j%coins[0]==0){
                dp[0][j]=1;
            }else{
                dp[0][j]=0;
            }
        }
        for(int i=0;i<n;++i){
            dp[i][0]=1;
        }
        for(int i=1;i<n;++i){
            for(int j=1;j<=amount;++j){
                dp[i][j]=dp[i-1][j];
                if(j-coins[i]>=0){
                    dp[i][j]+=dp[i][j-coins[i]];
                }
            }
        }
        
        return dp[n-1][amount];
    }
    int change(int amount, vector<int>& coins) {
        return DP(coins,amount);
    }
};

在这里插入图片描述


零钱兑换

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    int DP(vector<int>& coins, int amount){
        vector<int>dp(amount+1,INT_MAX);
        //第一列初始化0,凑成0所需硬币0个
        dp[0]=0;
        for(int i=0;i<coins.size();++i){
            for(int j=0;j<=amount;++j){
                if(j>=coins[i]&&dp[j-coins[i]]<INT_MAX){
                    dp[j]=min(dp[j],dp[j-coins[i]]+1);
                }
            }
        }
        return dp[amount]==INT_MAX?-1:dp[amount];
    }
    int coinChange(vector<int>& coins, int amount) {
        return DP(coins,amount);
    }
};

在这里插入图片描述


组合总和 Ⅳ

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    int DP(vector<int>& nums, int target){
        int n=nums.size();
        vector<int>dp(target+1,0);
        dp[0]=1;
        for(int i=1;i<=target;++i){
            for(int j:nums){
                if(i>=j&&dp[i]<INT_MAX-dp[i-j]){
                    dp[i]+=dp[i-j];
                }
            }
        }
        return dp[target];
    }
    int combinationSum4(vector<int>& nums, int target) {
        return DP(nums,target);
    }
};

在这里插入图片描述


完全平方数

在这里插入图片描述

class Solution {
public:
    int DP(int n){
        int dp[n+1];
        dp[0]=0;
        dp[1]=1;
        for(int i=2;i<=n;++i){
            //先求<i的最大的的平方数k*k
            int k=process(i);
            //dp[i]=min{dp[i-1*1],dp[i-2*2],...dp[i-k*k]}+1
            int min=INT_MAX;
            for(int j=1;j<=k;++j){
                min=std::min(min,dp[i-j*j]);
            }
            // cout<<min<<endl;
            dp[i]=min+1;
        }
        return dp[n];
    }
    int process(int n){
        int left=1;
        int right=sqrt(n);
        int mid;
        while(left<right){
            mid=left+((right-left)>>1);
            if(mid*mid==n){
                return mid-1;
            }
            else if(mid*mid<n){
                left=mid+1;
            }else{
                right=mid-1;
            }
        }
        return left;
    }
    int numSquares(int n) {
        return DP(n);
        
    }
};

在这里插入图片描述


不同的二叉搜索树

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    int DP(int n){
        int dp[n+1];
        if(n==1)return 1;
        if(n==2)return 2;
        dp[0]=1;
        dp[1]=1;
        dp[2]=2;
        //dp[i]:有i个节点可以构造的二叉搜索树的个数
        for(int i=3;i<=n;++i){
            dp[i]=0;
            for(int j=0;j<i;++j){//左树有j个节点,右树有(i-j-1)个节点
                dp[i]+=dp[j]*dp[i-j-1]; 
 //dp[i]= 左树有j个节点可以构造的二叉搜索树的个数*右树有(i-j-1)个节点可以构造的二//叉搜索树的个数
            }
        }
        return dp[n];
    }
    int numTrees(int n) {
        return DP(n);
    }
};

在这里插入图片描述


跳跃游戏 II

在这里插入图片描述

在这里插入图片描述

class Solution {
public:
    int DP(vector<int>& nums){
        int dp[nums.size()];
        dp[0]=nums[0];
        for(int i=1;i<nums.size();++i){
            dp[i]=max(dp[i-1]-1,nums[i]);
        }
        int loc=0;
        int ans=0;
        while(loc<nums.size()-1){
            ans++;
            loc+=dp[loc];

        }
        return ans;
        //2 3 2 1 4 
    }
    int jump(vector<int>& nums) {
        if(nums.size()==1)return 0;
        return DP(nums);

        
    }
    
};

在这里插入图片描述


跳跃游戏

在这里插入图片描述

class Solution {
public:
    bool DP(vector<int>& nums){
        int dp[nums.size()];
        dp[0]=nums[0];
        for(int i=1;i<nums.size();++i){
            if(dp[i-1]==0)return false;
            dp[i]=max(nums[i],dp[i-1]-1);
        }
        return true;
    }
    bool canJump(vector<int>& nums) {
        return DP(nums);
    }
};

在这里插入图片描述


分割等和子集

在这里插入图片描述

解题思路:

dp[i] : 是否有子集和等于 i

转移方程: dp[i] |= dp[ i-nums[j] ]

class Solution {
public:
    int All;
    bool DP(vector<int>& nums){
        bool dp[(All>>1)+1];
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        for(int i=0;i<nums.size();++i){

            for(int j=(All>>1);j>=nums[i];--j){
                dp[j]|=dp[j-nums[i]];
            }
        }
        return dp[All>>1];
    }
    bool canPartition(vector<int>& nums) {
        if(nums.size()==1)return false;
        int all=0;
        for(int i:nums){
            all+=i;
        }
        if((all&1)==1)return false;
        All=all;
        // return process(nums,0,0);
        return DP(nums)>0?true:false;
    }
};

在这里插入图片描述


按摩师


在这里插入图片描述

在这里插入图片描述

class Solution {
    public int process(int[] nums,int index,int sum){//默认当前位置是可以选的
        if(index==nums.length){
            return sum;
        }
        if(index==nums.length-1){
            return sum+nums[index];
        }
        return Math.max(process(nums,index+1,sum),process(nums,index+2,sum+nums[index]));
    }
    public int DP(int[] nums) {
		//index: 0~nums.length
        if(nums==null||nums.length==0)return 0;
		int[] dp=new int[nums.length+1];

		dp[nums.length-1]=nums[nums.length-1];
		for(int i=nums.length-2;i>=0;--i) {
			dp[i]=Math.max(dp[i+1], dp[i+2]+nums[i]);
		}
		return Math.max(dp[0], dp[1]);
	}
    public int massage(int[] nums) {
        return DP(nums);
    }
}

在这里插入图片描述



除数博弈

在这里插入图片描述
在这里插入图片描述

class Solution {
    //who: 0:爱丽丝 1:鲍勃
    public boolean process(int n,int who){
        if(n==1){
            if(who==0){
                return false;
            }else{
                return true;
            }
        }
        //n>=2
        boolean ans=false;
        if(who==0){//轮到爱丽丝
            for(int i=(int)Math.sqrt(n);i>=1;--i){
                if(n%i==0){
                    ans=process(n-i,1);
                }
            }
        }//轮到鲍勃
        else{
            for(int i=(int)Math.sqrt(n);i>=1;--i){
                if(n%i==0){
                    ans=process(n-i,0);
                }
            }
        }
        return ans;
    
    }
    public boolean DP(int n) {
    	//n: 1~n
    	boolean[] dp0=new boolean[n+1];
    	boolean[] dp1=new boolean[n+1];
    	dp0[1]=false;
    	dp1[1]=true;
    	for(int i=2;i<=n;++i) {
    		
    		for(int j=(int)Math.sqrt(i);j>=1;--j) {
    			if(i%j==0) {
    				dp0[i]=dp1[i-j];
    				dp1[i]=dp0[i-j];
    			}
    		}
    	}
    	
    	return dp0[n];
    }
    public boolean divisorGame(int n) {
        return DP(n);

    }
}

在这里插入图片描述



使用最小花费爬楼梯

在这里插入图片描述
在这里插入图片描述

class Solution {
    public int process(int[] cost,int index,int sum){
        if(index>=cost.length){//已经没有台阶了,花费为0
            return sum;
        }
        if(index==cost.length-1){//最后的台阶
            return sum+cost[index];
        }
        //还没有到最后一个台阶
        int ans=0;
        ans=sum+process(cost,index+1,sum+cost[index]);
        ans=Math.min(ans,sum+process(cost,index+2,sum+cost[index]));
        return ans;
    }
    public int DP(int[] cost) {
		//index: 0~cost.length 
		int[] dp=new int[cost.length+1];
		dp[cost.length-1]=cost[cost.length-1];
		for(int i=cost.length-2;i>=0;--i) {
			dp[i]=Math.min(dp[i+1], dp[i+2])+cost[i];
		}
		return Math.min(dp[0],dp[1]);
	}
    public int minCostClimbingStairs(int[] cost) {
        return DP(cost);
    }
}

在这里插入图片描述



比特位计数

在这里插入图片描述

在这里插入图片描述


题解:

对于一个二进制数来说,如果它的 最低位为1 (%2 为 1),则它与 n/2 的 1 个数相差1。 如果它的 最低位为 0,则它与 n/2 的 1 个数相同


class Solution {
    public int[] DP(int n){
        int[] dp=new int[n+1];
        if(n==0)return dp;
        dp[1]=1;
        for(int i=2;i<=n;++i){
            //i是偶数
            if((i&1)==0){
                dp[i]=dp[i>>1];
            }
            //i是奇数
            else{
                dp[i]=dp[i>>1]+1;
            }
        }
        return dp;
    }
    public int[] countBits(int n) {
        return DP(n);
    }
}

在这里插入图片描述



爬楼梯

在这里插入图片描述
在这里插入图片描述

class Solution {

    //暴力尝试
    public int process(int rest){
        if(rest<0){
            return 0;
        }
        if(rest==0||rest==1){
            return 1;
        }
        //rest>0

        return process(rest-1)+process(rest-2);

    }
    //动态规划
    public int DP(int n) {
    	//rest: 0~n
    	int[] dp=new int[n+1];
    	dp[0]=1;
    	dp[1]=1;
    	for(int i=2;i<=n;++i) {
    		dp[i]=dp[i-1]+dp[i-2];
    	}
    	return dp[n];
    }
    public int climbStairs(int n) {
        return DP(n);
    }
}

在这里插入图片描述



机器人到达指定位置方法数

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


import java.util.Scanner;

public class Robot {
	public static int ways(int N,int P,int cur,int rest) {
		if(rest==0) {
			return cur==P?1:0;
		}
		if(cur==1)return ways(N,P,cur+1,rest-1);
		if(cur==N)return ways(N,P,cur-1,rest-1);
		return ways(N,P,cur-1,rest-1)+ways(N,P,cur+1,rest-1);
	}
	public static int getAns(int N,int P,int M,int K) {
		if(M<1||M>N)return 0;
		return ways(N,P,M,K);
	}
	public static int waysDP(int N,int P,int M,int K) {
		//cur: 1~N  rest: 0~K
		int[][] dp=new int[N+1][K+1];
		dp[P][0]=1;
		for(int col=1;col<=K;++col) {
			dp[1][col]=dp[2][col-1];
			for(int row=2;row<N;++row) {
				dp[row][col]=(dp[row-1][col-1]+dp[row+1][col-1])%(1000000007);
			}
			dp[N][col]=dp[N-1][col-1];
		}
		return dp[M][K]%(1000000007);
	}
	public static int Ans(int N,int P,int M,int K) {
		if(M<1||M>N)return 0;
		return waysDP(N,P,M,K);
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int N,M,K,P;
		N=scan.nextInt();
		M=scan.nextInt();
		K=scan.nextInt();
		P=scan.nextInt();
//		System.out.println(getAns(N,P,M,K));
		System.out.println(Ans(N,P,M,K));
	}

}

在这里插入图片描述



排成一条线的纸牌博弈问题

在这里插入图片描述


import java.util.Scanner;

public class Main {
	public static int win(int[] arr,int L,int R) {
		return Math.max(f(arr,L,R),s(arr,L,R));
	}
	public static int f(int[] arr,int L,int R) {
		if(L==R)return arr[L];
		return Math.max(arr[L]+s(arr,L+1,R), arr[R]+s(arr,L,R-1));
	}
	public static int s(int[] arr,int L,int R) {
		if(L==R)return 0;
		return Math.min(f(arr,L+1,R),f(arr,L,R-1));
	}
	public static int winDP(int[] arr,int L,int R) {
		//L: 0~arr.length-1  R: 0~arr.length-1
		int[][] f=new int[arr.length][arr.length];
		int[][] s=new int[arr.length][arr.length];
		for(int i=0;i<arr.length;++i) {
			f[i][i]=arr[i];
		}
		for(int col=1;col<arr.length;++col) {
			
			int row=0,j=col;
			while(row<arr.length&&j<arr.length) {
				f[row][j]=Math.max(arr[row]+s[row+1][j],arr[j]+s[row][j-1]);
				s[row][j]=Math.min(f[row+1][j], f[row][j-1]);
				row++;
				j++;
			}
		}
		return Math.max(f[L][R],s[L][R]);
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		int[] arr=new int[n];
		for(int i=0;i<n;++i) {
			arr[i]=scan.nextInt();
		}
//		System.out.println(win(arr,0,n-1));
		System.out.println(winDP(arr,0,n-1));
	}

}

在这里插入图片描述



象棋中马的跳法

在这里插入图片描述

import java.util.Scanner;

public class Main {
	public static int ways(int x,int y,int curx,int cury,int rest) {
		//x:0~8 y:0~9 rest:0~k
		if(rest==0) {
			if(curx==x&&cury==y)return 1;
			else return 0;
		}
		int ans=0;
		if(curx-1>=0&&curx-1<9&&cury+2>=0&&cury+2<10) {
			ans+=ways(x,y,curx-1,cury+2,rest-1);
		}
		if(curx+1>=0&&curx+1<9&&cury+2>=0&&cury+2<10) {
			ans+=ways(x,y,curx+1,cury+2,rest-1);
		}
		if(curx-2>=0&&curx-2<9&&cury+1>=0&&cury+1<10) {
			ans+=ways(x,y,curx-2,cury+1,rest-1);
		}
		if(curx+2>=0&&curx+2<9&&cury+1>=0&&cury+1<10) {
			ans+=ways(x,y,curx+2,cury+1,rest-1);
		}
		if(curx-2>=0&&curx-2<9&&cury-1>=0&&cury-1<10) {
			ans+=ways(x,y,curx-2,cury-1,rest-1);
		}
		if(curx+2>=0&&curx+2<9&&cury-1>=0&&cury-1<10) {
			ans+=ways(x,y,curx+2,cury-1,rest-1);
		}
		if(curx-1>=0&&curx-1<9&&cury-2>=0&&cury-2<10) {
			ans+=ways(x,y,curx-1,cury-2,rest-1);
		}
		if(curx+1>=0&&curx+1<9&&cury-2>=0&&cury-2<10) {
			ans+=ways(x,y,curx+1,cury-2,rest-1);
		}
		return ans;
	}
	public static int waysDP(int x,int y,int k) {
		int[][][] dp=new int[10][9][k+1];
		dp[x][y][0]=1;
		for(int l=1;l<=k;++l) {
			for(int row=0;row<10;++row) {
				for(int col=0;col<9;++col) {
					if(row-2>=0&&row-2<10&&col-1>=0&&col-1<9) {
						dp[row][col][l]+=dp[row-2][col-1][l-1];
					}
					if(row-2>=0&&row-2<10&&col+1>=0&&col+1<9) {
						dp[row][col][l]+=dp[row-2][col+1][l-1];
					}
					if(row-1>=0&&row-1<10&&col-2>=0&&col-2<9) {
						dp[row][col][l]+=dp[row-1][col-2][l-1];
					}
					if(row-1>=0&&row-1<10&&col+2>=0&&col+2<9) {
						dp[row][col][l]+=dp[row-1][col+2][l-1];
					}
					if(row+1>=0&&row+1<10&&col-2>=0&&col-2<9) {
						dp[row][col][l]+=dp[row+1][col-2][l-1];
					}
					if(row+1>=0&&row+1<10&&col+2>=0&&col+2<9) {
						dp[row][col][l]+=dp[row+1][col+2][l-1];
					}
					if(row+2>=0&&row+2<10&&col-1>=0&&col-1<9) {
						dp[row][col][l]+=dp[row+2][col-1][l-1];
					}
					if(row+2>=0&&row+2<10&&col+1>=0&&col+1<9) {
						dp[row][col][l]+=dp[row+2][col+1][l-1];
					}
				}
			}
		}
		return dp[0][0][k];
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int x,y,k;
		x=scan.nextInt();
		y=scan.nextInt();
		k=scan.nextInt();
		//System.out.println(ways(x,y,0,0,k));
		System.out.println(waysDP(x,y,k));
	}

}

在这里插入图片描述



Bob的生存概率

在这里插入图片描述

import java.util.Scanner;

public class Main {
	public static int process(int N,int M,int row,int col,int rest) {
		if(row<0||row>=N||col<0||col>=M)return 0;
		if(rest==0) {
			if(row>=0&&row<N&&col>=0&&col<M)return 1;
			else return 0;
		}
		int ans=0;
		if(row-1>=0)ans+=process(N,M,row-1,col,rest-1);
		if(row+1<N)ans+=process(N,M,row+1,col,rest-1);
		if(col-1>=0)ans+=process(N,M,row,col-1,rest-1);
		if(col+1<M)ans+=process(N,M,row,col+1,rest-1);
		return ans;
	}
	public static long DP(int N,int M,int i,int j,int k) {
		//row: 0~N-1  col: 0~M-1  rest: 0~k
		long[][][] dp=new long[N][M][k+1];
		for(int row=0;row<N;++row) {
			for(int col=0;col<M;++col) {
				dp[row][col][0]=1;
			}
		}
		for(int l=1;l<=k;++l) {
			for(int row=0;row<N;++row) {
				for(int col=0;col<M;++col) {
					if(row-1>=0)dp[row][col][l]+=dp[row-1][col][l-1];
					if(row+1<N)dp[row][col][l]+=dp[row+1][col][l-1];
					if(col-1>=0)dp[row][col][l]+=dp[row][col-1][l-1];
					if(col+1<M)dp[row][col][l]+=dp[row][col+1][l-1];
				}
			}
			
		}
		
		
		return dp[i][j][k];
		
	}
	public static long pow(int a,int b) {
		long res=1;
		for(int i=1;i<=b;++i) {
			res*=a;
		}
		return res;
	}
	public static long gcd(long m,long n) {
		return n==0?m:gcd(n,m%n);
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int N,M,i,j,k;
		N=scan.nextInt();
		M=scan.nextInt();
		i=scan.nextInt();
		j=scan.nextInt();
		k=scan.nextInt();
		//int ans1=process(N,M,i,j,k);
		long all=pow(4,k);
		//long g1=gcd(ans1,all);
		//System.out.println(ans1/g1+"/"+all/g1);
		long ans2=DP(N,M,i,j,k);
		long g2=gcd(ans2,all);
		System.out.println(ans2/g2+"/"+all/g2);
	}

}

在这里插入图片描述



硬币数

在这里插入图片描述

class Solution {
    public int ways(int[] arr,int index,int rest){
        if(index==arr.length){
            return rest==0?1:0;
        }
        int ans=0;
        for(int i=0;i*arr[index]<=rest;++i){
            ans+=ways(arr,index+1,rest-i*arr[index])%1000000007;
        }
        return ans%1000000007;
    }
    public int waysDP(int[] arr,int n){
        //index: 0~arr.length  rest: 0~n
        int[][] dp=new int[arr.length+1][n+1];
        dp[arr.length][0]=1;
        for(int row=arr.length-1;row>=0;--row){
            for(int col=0;col<=n;++col){
                dp[row][col]=dp[row+1][col];
                if(col-arr[row]>=0){
                    dp[row][col]+=dp[row][col-arr[row]]%1000000007;
                }
            }
        }
        return dp[0][n]%1000000007;
    }
    public int waysToChange(int n) {
        int[] arr=new int[]{25,10,5,1};
        return waysDP(arr,n);
    }
}

在这里插入图片描述



子数组的最大累加和

在这里插入图片描述

在这里插入图片描述

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int N=scan.nextInt();
		int[] arr=new int[N];
		scan.nextLine();
		String[] num=scan.nextLine().split(" ");
		for(int i=0;i<N;++i) {
			arr[i]=Integer.parseInt(num[i]);
		}
		int cur=0;
		int max=Integer.MIN_VALUE;
		for(int i=0;i<N;++i) {
			cur+=arr[i];
			max=Math.max(max, cur);
			if(cur<0) {
				cur=0;
			}
		}
		System.out.println(max);
	}
	

}

在这里插入图片描述



子矩阵的最大累加和

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

import java.util.Scanner;

public class Main {
	public static int getSumMax(int[] arr) {
		int cur=0;
		int max=Integer.MIN_VALUE;
		for(int i=0;i<arr.length;++i) {
			cur+=arr[i];
			max=Math.max(max, cur);
			if(cur<0) {
				cur=0;
			}
		}
		return max;
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int row=scan.nextInt();
		int col=scan.nextInt();
		int[][] arr=new int[row][col];
		for(int i=0;i<row;++i) {
			for(int j=0;j<col;++j) {
				arr[i][j]=scan.nextInt();
			}
		}
		int ans=Integer.MIN_VALUE;
		for(int i=0;i<row;++i) {
			for(int j=i;j<row;++j) {
				int[] sum=new int[col];
				for(int c=0;c<col;++c) {
					for(int k=i;k<=j;++k) {
						sum[c]+=arr[k][c];
					}
				}
				ans=Math.max(ans, getSumMax(sum));
			}
		}
		System.out.println(ans);
	}
	

}

在这里插入图片描述



最小路径和

在这里插入图片描述

在这里插入图片描述

import java.util.Scanner;

public class Main {
	
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		int m=scan.nextInt();
		int[][] arr=new int[n][m];
		for(int i=0;i<n;++i) {
			for(int j=0;j<m;++j) {
				arr[i][j]=scan.nextInt();
			}
		}
		int[][] dp=new int[n][m];
		dp[0][0]=arr[0][0];
		for(int col=1;col<m;++col) {
			dp[0][col]=dp[0][col-1]+arr[0][col];
		}
		for(int row=1;row<n;++row) {
			dp[row][0]=dp[row-1][0]+arr[row][0];
		}
		for(int row=1;row<n;++row) {
			for(int col=1;col<m;++col) {
				dp[row][col]=Math.min(dp[row][col-1], dp[row-1][col])+arr[row][col];
			}
		}
		System.out.println(dp[n-1][m-1]);
	}

}

在这里插入图片描述



最长公共子序列

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import java.util.*;


public class Solution {
    /**
     * longest common subsequence
     * @param s1 string字符串 the string
     * @param s2 string字符串 the string
     * @return string字符串
     */
    public String LCS (String s1, String s2) {
        // write code here
        if(s1==null||s2==null||s1.length()==0||s2.length()==0)return String.valueOf(-1);
	       int[][] dp=new int[s1.length()][s2.length()];
	       int col;
	       for(col=0;col<s2.length();++col) {
	    	   if(s1.charAt(0)==s2.charAt(col)) {
	    		   break;
	    	   }
	       }
	       for(int i=col;i<s2.length();++i) {
	    	   dp[0][i]=1;
	       }
	       int row;
	       for(row=0;row<s1.length();++row) {
	    	   if(s1.charAt(row)==s2.charAt(0)) {
	    		   break;
	    	   }
	       }
	       for(int i=row;i<s1.length();++i) {
	    	   dp[i][0]=1;
	       }
	       for(row=1;row<s1.length();++row) {
	    	   for(col=1;col<s2.length();++col) {
	    		   dp[row][col]=Math.max(dp[row-1][col], Math.max(dp[row][col-1], dp[row-1][col-1]));
	    		   if(s1.charAt(row)==s2.charAt(col)) {
	    			   dp[row][col]=Math.max(dp[row][col],1+dp[row-1][col-1]);
	    		   }
	    	   }
	       }
	       if(dp[s1.length()-1][s2.length()-1]==0)return String.valueOf(-1);
	       row=s1.length()-1;
	       col=s2.length()-1;
	       int len=dp[s1.length()-1][s2.length()-1];
	       char[] chs=new char[len];
	       int cur=len-1;
	       while(row>=1&&col>=1) {
	    	   if(s1.charAt(row)==s2.charAt(col)) {
	    		   if(cur<0)break;
	    		  chs[cur]=s1.charAt(row);
//	    		  System.out.print(chs[cur]+" ");
	    		  cur--;
	    		  row--;col--;
	    	   }else {
	    		   if(dp[row][col-1]>dp[row-1][col]) {
	    			   col--;
	    		   }else {
	    			   row--;
	    		   }
	    	   }
	       }
	       if(dp[row][col]==1) {
	    	   if(row==0) {
	    		   chs[cur]=s1.charAt(row);
	    	   }else {
	    		   chs[cur]=s2.charAt(col);
	    	   }
	    		   
	       }
	      
	       return String.valueOf(chs);
    }
}

在这里插入图片描述



最长公共子串

在这里插入图片描述

空间复杂度 O ( n ∗ m ) O(n*m) O(nm)

import java.util.Scanner;

public class Main {
	public static String process(String s1,String s2) {
		if(s1==null||s2==null||s1.length()==0||s2.length()==0)return String.valueOf(-1);
		int[][] dp=new int[s1.length()][s2.length()];
		int end=0;
		int len=0;
		for(int col=0;col<s2.length();++col) {
			if(s2.charAt(col)==s1.charAt(0)) {
				dp[0][col]=1;
				len=1;
			}
		}
		for(int row=0;row<s1.length();++row) {
			if(s1.charAt(row)==s2.charAt(0)) {
				dp[row][0]=1;
				end=row;
			}
		}
		for(int row=1;row<s1.length();++row) {
			for(int col=1;col<s2.length();++col) {
				if(s1.charAt(row)==s2.charAt(col)) {
					dp[row][col]=1+dp[row-1][col-1];
					if(len<=1+dp[row-1][col-1]) {
						len=1+dp[row-1][col-1];
						end=row;
//						System.out.println(end);
					}
				}
			}
		}
        if(len==0)return String.valueOf(-1);
		return s1.substring(end-len+1,end+1);
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		String s1=scan.nextLine();
		String s2=scan.nextLine();
		System.out.println(process(s1,s2));
	}

}

在这里插入图片描述


空间复杂度 O ( 1 ) O(1) O(1)

import java.util.Scanner;

public class Main{

	public static String process(String s1,String s2) {
		if(s1==null||s2==null||s1.length()==0||s2.length()==0)return String.valueOf(-1);
		int end=0;
		int len=0;
		int dp=0;
		int i,j,t;
		for(int col=s2.length()-1;col>=0;--col) {
			i=0;
			j=col;
			t=0;
			while(i<s1.length()&&j<s2.length()) {
				if(s1.charAt(i)==s2.charAt(j)) {
					t++;
					if(t>len) {
						len=t;
						end=i;
					}
				}else {
					t=0;
				}
				i++;
				j++;
			}
		}
		for(int row=1;row<s1.length();++row) {
			j=0;
			i=row;
			t=0;
			while(i<s1.length()&&j<s2.length()) {
				if(s1.charAt(i)==s2.charAt(j)) {
					t++;
					if(t>len) {
						len=t;
						end=i;
					}
				}else {
					t=0;
				}
				i++;
				j++;
			}
		}
		
		if(len==0)return String.valueOf(-1);
		return s1.substring(end-len+1,end+1);
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		String s1=scan.nextLine();
		String s2=scan.nextLine();
		System.out.println(process(s1,s2));
	}

}

在这里插入图片描述



最长递增子序列

在这里插入图片描述

import java.util.*;

public class AscentSequence {
    public int process(int[] arr,int a,int b,int x){//二分
        int left=a;
        int right=b;
        int mid=left+((right-left)>>2);
        if(x>arr[b])return -1;
        while(left<=right){
            if(arr[mid]>=x){
                right=mid-1;
            }else{
                left=mid+1;
            }
            mid=left+((right-left)>>2);
        }
        return left;
    }
    public int findLongest(int[] A, int n) {
        // write code here
        int[] ends=new int[n];
        int[] dp=new int[n];
        int max=0;
        dp[0]=1;
        ends[0]=A[0];
        int cur=0;
        max=Math.max(max,dp[0]);
        for(int i=1;i<n;++i){
            int index=process(ends,0,cur,A[i]);
            if(index==-1){
                ends[++cur]=A[i];
                dp[i]=cur+1;
                max=Math.max(max,dp[i]);
            }else{
                ends[index]=A[i];
                dp[i]=index+1;
                max=Math.max(max,dp[i]);
            }
        }
        
        return max;
    }
}

在这里插入图片描述



在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    int DP(vector<int>& nums){
        int n=nums.size();
        vector<int>dp(n,0);
        //dp[i]:以nums[i]结尾的最长递增子序列
        dp[0]=1;
        int res=1;
        if(n==1)return dp[0];
        for(int i=1;i<n;++i){
            dp[i]=1;
            for(int j=0;j<i;++j){
                
                if(nums[i]>nums[j]){
                    dp[i]=max(dp[i],dp[j]+1);
                }
            }
            res=max(res,dp[i]);
        }
        return res;
    }
    int lengthOfLIS(vector<int>& nums) {
        return DP(nums);
    }
};

在这里插入图片描述


输出最长递增子序列

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


import java.util.Scanner;

public class Main {
	public static int process(int[] arr,int a,int b,int x){//二分
        int left=a;
        int right=b;
        int mid=left+((right-left)>>2);
        if(x>arr[b])return -1;
        while(left<=right){
            if(arr[mid]>=x){
                right=mid-1;
            }else{
                left=mid+1;
            }
            mid=left+((right-left)>>2);
        }
        return left;
    }
    public static void findLongest(int[] A, int n) {
        // write code here
        int[] ends=new int[n];
        int[] dp=new int[n];
        int max=0;
        dp[0]=1;
        ends[0]=A[0];
        int cur=0;
        max=Math.max(max,dp[0]);
        int end=0;
        for(int i=1;i<n;++i){
            int index=process(ends,0,cur,A[i]);
            
            if(index==-1){
                ends[++cur]=A[i];
                dp[i]=cur+1;
                max=Math.max(max,dp[i]);
                if(max==dp[i]) {
                	end=i;
                }
                
            }else{
                ends[index]=A[i];
                dp[i]=index+1;
                max=Math.max(max,dp[i]);
                if(max==dp[i]) {
                	end=i;
                }
            }
        }
        int[] ans=new int[max];
        cur=max-1;
        ans[cur--]=A[end];
        for(int i=end-1;i>=0;--i) {
        	if(A[i]<ans[cur+1]&&dp[i]==cur+1) {
        		ans[cur--]=A[i];
        	}
        }
        for(int i=0;i<max;++i) {
        	System.out.print(ans[i]+" ");
        }
    }
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		int[] arr=new int[n];
		scan.nextLine();
		String[] str=scan.nextLine().split(" ");
		for(int i=0;i<n;++i) {
			arr[i]=Integer.parseInt(str[i]);
		}
		findLongest(arr,n);
	}

}

在这里插入图片描述



信封问题

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;

public class Main{
	public static int process(int[] arr,int a,int b,int x){//二分
        int left=a;
        int right=b;
        int mid=left+((right-left)>>2);
        if(x>arr[b])return -1;
        while(left<=right){
            if(arr[mid]>=x){
                right=mid-1;
            }else{
                left=mid+1;
            }
            mid=left+((right-left)>>2);
        }
        return left;
    }
    public static int findLongest(int[] A, int n) {
        int[] ends=new int[n];
        int[] dp=new int[n];
        int max=0;
        dp[0]=1;
        ends[0]=A[0];
        int cur=0;
        max=Math.max(max,dp[0]);
        int end=0;
        for(int i=1;i<n;++i){
            int index=process(ends,0,cur,A[i]);
            
            if(index==-1){
                ends[++cur]=A[i];
                dp[i]=cur+1;
                max=Math.max(max,dp[i]);
                if(max==dp[i]) {
                	end=i;
                }
                
            }else{
                ends[index]=A[i];
                dp[i]=index+1;
                max=Math.max(max,dp[i]);
                if(max==dp[i]) {
                	end=i;
                }
            }
        }
        return max;
    }
    public static class Envelope{
    	public int l;
    	public int w;
    	public Envelope(int a,int b) {
    		l=a;
    		w=b;
    	}
    }
    public static class Compare implements Comparator<Envelope>{
    	public int compare(Envelope o1,Envelope o2) {
    		if(o1.l!=o2.l) {
    			return o1.l-o2.l;
    		}else {
    			return o2.w-o1.w;
    		}
    	}
    }
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		Envelope[] arr=new Envelope[n];
//		scan.nextLine();
		for(int i=0;i<n;++i) {
			arr[i]=new Envelope(scan.nextInt(),scan.nextInt());
		}
		Arrays.sort(arr,new Compare());
		int[] res=new int[n];
		for(int i=0;i<n;++i) {
			res[i]=arr[i].w;
		}
		
		System.out.println(findLongest(res,n));
	}

}

在这里插入图片描述



数字转换字符串

在这里插入图片描述
在这里插入图片描述


import java.util.Scanner;

public class Main {
	public static int process(String s,int index) {
		if(index==s.length())return 1;
		if(s.charAt(index)=='0')return 0;
		int ans=process(s,index+1);
		if(index==s.length()-1)return ans;
		int num=(s.charAt(index)-'0')*10+(s.charAt(index+1)-'0');
		if(num<27&&index+2<=s.length()) {
			return ans+process(s,index+2);
		}
		return ans;
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		String s=scan.nextLine();
		int ans=process(s,0);
		System.out.println(ans);
	}

}

在这里插入图片描述


import java.util.Scanner;

public class Main{

	public static int dpways(String s) {
		//index:0~s.length()
		if(s==null||s.length()==0)return 0;
		int[] dp=new int[s.length()+1];
		dp[s.length()]=1;
		dp[s.length()-1]=(s.charAt(s.length()-1)=='0'?0:1);
		for(int i=s.length()-2;i>=0;--i) {
			if(s.charAt(i)=='0')dp[i]=0;
			else {
				dp[i]=dp[i+1];
				int num=(s.charAt(i)-'0')*10+(s.charAt(i+1)-'0');
				if(num<27) {
					dp[i]+=dp[i+2];
				}
			}
		}
		return dp[0];
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		String s=scan.nextLine();
//		int ans=process(s,0);
		System.out.println(dpways(s));
	}

}

在这里插入图片描述



牛牛的背包问题

在这里插入图片描述
在这里插入图片描述

这道题 改进的暴力递归 可以通过,但是动态规划会异常,因为开辟的空间太大了,又不能空间压缩。


import java.util.Scanner;

public class Main{
	public static int process(int[] arr,int index,int rest) {
		if(rest<0) {
			return 0;
		}
		if(index==arr.length) {
			return 1;
		}
		int ans=process(arr,index+1,rest);
		ans+=process(arr,index+1,rest-arr[index]);
		return ans;
	}
	
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		int v=scan.nextInt();
		int[] arr=new int[n];
		scan.nextLine();
		String[] s=scan.nextLine().split(" ");
		long sum=0;
		for(int i=0;i<n;++i) {
			arr[i]=Integer.parseInt(s[i]);
			sum+=arr[i];
		}
		if(sum<=v) System.out.println(1<<n);
		else System.out.println(process(arr,0,v));
	}

}

在这里插入图片描述


import java.util.Scanner;

public class Main{
	
	public static int dpways(int[] arr,int v) {
		//index:0~arr.length  rest:0~v
		
		int[][] dp=new int[arr.length+1][v+1];
		for(int col=0;col<=v;++col) {
			dp[arr.length][col]=1;
		}
		for(int row=arr.length-1;row>=0;--row) {
			for(int col=0;col<=v;++col) {
				dp[row][col]=dp[row+1][col];
				if(col-arr[row]>=0) {
					dp[row][col]+=dp[row+1][col-arr[row]];
				}

			}

		}
		return dp[0][v];
	}
	
	
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		int v=scan.nextInt();
		int[] arr=new int[n];
		scan.nextLine();
		String[] s=scan.nextLine().split(" ");
	
		for(int i=0;i<n;++i) {
			arr[i]=Integer.parseInt(s[i]);
			
		}
		
		System.out.println(dpways(arr,v));
	}

}

在这里插入图片描述



最小编辑代价

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

import java.util.Scanner;

public class Main {
	public static int minEditCost(String s1,String s2,int ic,int dc,int rc) {
		int[][] dp=new int[s1.length()+1][s2.length()+1];
		for(int col=0;col<=s2.length();++col) {
			dp[0][col]=col*ic;
		}
		for(int row=1;row<=s1.length();++row) {
			dp[row][0]=row*dc;
		}
		for(int row=1;row<=s1.length();++row) {
			for(int col=1;col<=s2.length();++col) {
				//第一种可能性
				if(s1.charAt(row-1)==s2.charAt(col-1)) {
					dp[row][col]=dp[row-1][col-1];
				}
				else {
					dp[row][col]=dp[row-1][col-1]+rc;
				}
				//第二种可能性
				dp[row][col]=Math.min(dp[row][col], dp[row-1][col]+dc);
				//第三种可能性
				dp[row][col]=Math.min(dp[row][col], dp[row][col-1]+ic);
			}
		}
		
		return dp[s1.length()][s2.length()];
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		String s1=scan.nextLine();
		String s2=scan.nextLine();
		int ic=scan.nextInt();
		int dc=scan.nextInt();
		int rc=scan.nextInt();
		int ans=minEditCost(s1,s2,ic,dc,rc);
		System.out.println(ans);
				
	}

}

在这里插入图片描述



逻辑组合

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import java.util.Scanner;

public class Main{
	
	public static int process(String s,boolean desired,int L,int R) {
		if(L==R) {
			if(desired==true) {
				return s.charAt(L)=='1'?1:0;
			}else {
				return s.charAt(L)=='1'?0:1;
			}
		}
		int ans=0;
		if(desired==true) {
			for(int i=L+1;i<R;i+=2) {//以i位置的运算符结束
				switch(s.charAt(i)) {
					case '&':{
						ans+=process(s,true,L,i-1)*process(s,true,i+1,R);
						break;
					}
					case '|':{
						ans+=process(s,true,L,i-1)*process(s,true,i+1,R);
						ans+=process(s,true,L,i-1)*process(s,false,i+1,R);
						ans+=process(s,false,L,i-1)*process(s,true,i+1,R);
						break;
					}
					case '^':{
						ans+=process(s,true,L,i-1)*process(s,false,i+1,R);
						ans+=process(s,false,L,i-1)*process(s,true,i+1,R);
						break;
					}
				}
			}
		}
		else {
			for(int i=L+1;i<R;i+=2) {//以i位置的运算符结束
				switch(s.charAt(i)) {
					case '&':{
						ans+=process(s,true,L,i-1)*process(s,false,i+1,R);
						ans+=process(s,false,L,i-1)*process(s,true,i+1,R);
						ans+=process(s,false,L,i-1)*process(s,false,i+1,R);
						break;
					}
					case '|':{
						ans+=process(s,false,L,i-1)*process(s,false,i+1,R);
						break;
					}
					case '^':{
						ans+=process(s,true,L,i-1)*process(s,true,i+1,R);
						ans+=process(s,false,L,i-1)*process(s,false,i+1,R);
						break;
					}
				}
			}
		}
		return ans;
		
	}
	public static long dpways(String s,boolean desired) {
		//L:0~s.length()-1 R:0~s.length()-1
        if(s.length()%2==0)return 0;
		long[][] dpTrue=new long[s.length()][s.length()];
		long[][] dpFalse=new long[s.length()][s.length()];
		for(int i=0;i<s.length();i+=2) {
			if(s.charAt(i)=='1') {
				dpTrue[i][i]=1;
				dpFalse[i][i]=0;
			}else {
				dpTrue[i][i]=0;
				dpFalse[i][i]=1;
			}
		}
		int N=1000000007;
		for(int col=2;col<s.length();col+=2) {
			for(int row=col-2;row>=0;row-=2) {
                if(s.charAt(row)!='1'&&s.charAt(row)!='0'||s.charAt(col)!='1'&&s.charAt(col)!='0'){
                    //不合法的
                    return 0;
                }
				for(int k=row+1;k<col;k+=2) {
					switch(s.charAt(k)) {
						case '&':{
							dpTrue[row][col]+=dpTrue[row][k-1]*dpTrue[k+1][col];
							dpFalse[row][col]+=dpTrue[row][k-1]*dpFalse[k+1][col];
							dpFalse[row][col]+=dpFalse[row][k-1]*dpTrue[k+1][col];
							dpFalse[row][col]+=dpFalse[row][k-1]*dpFalse[k+1][col];
							break;
						}
						case '|':{
							dpTrue[row][col]+=dpTrue[row][k-1]*dpTrue[k+1][col];
							dpTrue[row][col]+=dpTrue[row][k-1]*dpFalse[k+1][col];
							dpTrue[row][col]+=dpFalse[row][k-1]*dpTrue[k+1][col];
							dpFalse[row][col]+=dpFalse[row][k-1]*dpFalse[k+1][col];
							break;
						}
						case '^':{
							dpTrue[row][col]+=dpTrue[row][k-1]*dpFalse[k+1][col];
							dpTrue[row][col]+=dpFalse[row][k-1]*dpTrue[k+1][col];
							dpFalse[row][col]+=dpTrue[row][k-1]*dpTrue[k+1][col];
							dpFalse[row][col]+=dpFalse[row][k-1]*dpFalse[k+1][col];
							break;
						}
					}
					dpTrue[row][col] %= 1000000007;
                    dpFalse[row][col] %= 1000000007;
				}
			}
		}
		if(desired)return dpTrue[0][s.length()-1]%N;
		return dpFalse[0][s.length()-1]%N;
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		String s=scan.nextLine();
		boolean desired=scan.nextBoolean();
		System.out.println(dpways(s,desired));
	}

}

在这里插入图片描述



三个无重叠子数组的最大和

在这里插入图片描述

class Solution {
    public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
        
        int[] dpleft=new int[nums.length];
		int sum=0;
		for(int i=0;i<k;++i) {
			sum+=nums[i];
		}
		dpleft[k-1]=sum;
		int[] add1=new int[nums.length];
		add1[k-1]=sum;

		for(int i=k;i<nums.length;++i) {
			add1[i]=add1[i-1]-nums[i-k]+nums[i];
		}
		int[] left=new int[nums.length];
		left[k-1]=0;
		for(int i=k;i<nums.length;++i) {
			if(dpleft[i-1]>=add1[i]) {
				left[i]=left[i-1];
				dpleft[i]=dpleft[i-1];
			}else {
				left[i]=i-k+1;
				dpleft[i]=add1[i];
			}
		}
		
		int[] right=new int[nums.length];
		int[] dpright=new int[nums.length];
		right[nums.length-k]=nums.length-1;
		int[] add2=new int[nums.length];
		sum=0;
		for(int i=nums.length-1;i>=nums.length-k;--i) {
			sum+=nums[i];
		}
		add2[nums.length-k]=sum;
		for(int i=nums.length-k-1;i>=0;--i) {
			add2[i]=add2[i+1]-nums[i+k]+nums[i];
		}
		right[nums.length-k]=nums.length-k;
		dpright[nums.length-k]=add2[nums.length-k];
		for(int i=nums.length-k-1;i>=0;--i) {
			if(add2[i]>=dpright[i+1]) {
				right[i]=i;
				dpright[i]=add2[i];
			}else {
				right[i]=right[i+1];
				dpright[i]=dpright[i+1];
			}
		}
		int[] res=new int[3];
		int max=Integer.MIN_VALUE;
		for(int i=k;i<=nums.length-2*k;++i) {
			int a=left[i-1];
			int b=i;
			int c=right[i+k];
			if(add2[a]+add2[i]+add2[c]>max) {
				max=add2[a]+add2[i]+add2[c];
				res[0]=a;
				res[1]=b;
				res[2]=c;
			}
		}
		
		return res;
    }
}

在这里插入图片描述







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值