leetcode动态规划第三期

之前漏了一题是leetcode的115题,S子序列包含T的种类

public class 动态规则之S子序列包含T的种类_115 {
	 public int numDistinct(String s, String t) {
		int lenS=s.length();
		int lenT=t.length();
		//s从0-i截取字符串的子串包含t的种类个数
		int [][] dp=new int[lenS+1][lenT+1];
		//两个都为空时候,s包含t,只有一种情况
		dp[0][0]=1;
		//t为空串时候,只有一种情况
		for (int i = 1; i <lenS; i++) {
			dp[i][0]=1;
		} 
		//s为空串时候,为0中情况
		for (int i = 1; i <lenT; i++) {
			dp[0][i]=0;
		}
		for (int i = 1; i <=lenS; i++) {
			for (int j = 1; j <=lenT; j++) {
				dp[i][j]=dp[i-1][j];
				if (s.charAt(i-1)==t.charAt(j-1)) {
					dp[i][j]+=dp[i-1][j-1];
				}
			}
		}
		return dp[lenS][lenT];
	 }
}

还有几种Dp情况,我在列举01背包问题,例如华为机试题: 购物单--链接:

http://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4?tpId=37&tqId=21239&rp=&ru=/ta/huawei&qru=/ta/huawei/question-ranking

package com.example.oj;

import java.util.Scanner;
 
public class 动态规划之0_1背包问题{
 
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int sum_money = 0;
        int num = 0;           
        sum_money=sc.nextInt();
        num=sc.nextInt();
        int price[]=new int[num+1];
        int val[]=new int[num+1];
        int[] q = new int[num+1];
        for (int i = 1; i <= num; i++) {
            price[i]=sc.nextInt();
            val[i]=sc.nextInt()*price[i];
            q[i]=sc.nextInt();
        }
        int[][] dp=new int[num+1][sum_money+1];
/*
* 初始值java默认赋值为0,其中dp[0][0...sum_money]为0,从dp[1][0...sum_money]
  计算第1行,代表第一件物品
dp[i][sum_money] : 前i个物体放入容量为sum_money的背包的最大价值;
dp[i-1][sum_money] : 前i-1个物体放入容量为sum_money的背包的最大价值;
dp[i-1][sum_money-price[i]] : 前i-1个物体放入容量为sum_money-price[i]的背包的最大价值;
dp[i][sum_money]=Math.max{dp[i-1][sum_money-price[i]]+val[i] , dp[i-1][sum_money]}
*/
        for (int i = 1; i <=num; i++) {
            for (int j = 1; j <= sum_money; j++) {
                if(q[i]==0)
                {
                    if(price[i]<=j)
                        dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-price[i]]+val[i]);
                }
                if(q[i]>0)
                {
                    if(price[i]+price[q[i]]<=j)
                        dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-price[i]-price[q[i]]]+val[i]+val[q[i]]);
                }
            }
             
        }
        System.out.println(dp[num][sum_money]);
    }
 
}
还有什么最长公共子串,最长公共子序列问题:

package com.example.oj;
public class 动态规划之最长公共连续子串 {
	public static void main(String[] args) {
		动态规划之最长公共连续子串 test = new 动态规划之最长公共连续子串();
        String A="binghaven";
        String B="jingseven";
		int lcString = getLCString(A,A.length(),B,B.length());
		System.out.println(lcString);
	}

	private static int getLCString(String a, int n, String b, int m) {
		char[] charA = a.toCharArray();
		char[] charB= b.toCharArray();
		
		//必须以dp[i][j]中charA[i]和charB【j】为结尾的最长子串
		int [][]dp=new int [n][m];
		String [][]dpStr=new String[n][m];
		for (int i = 0; i <n; i++) {
			for (int j = 0; j < m; j++) {
				dpStr[i][j]="";
			}
		}
		for (int i = 0; i < n; i++) {
			if (charA[i]==charB[0]) {
				dp[i][0]=1;
				dpStr[i][0]=""+charA[i];
			}
		}
		for (int i = 0; i < m; i++) {
			if (charA[0]==charB[i]) {
				dp[0][i]=1;
				dpStr[0][i]=""+charB[i];
			}
		}
		for (int i = 1; i < n; i++) {
			for (int j = 1; j < m; j++) {
				if (charA[i]==charB[j]) {
					dp[i][j]=dp[i-1][j-1]+1;
					dpStr[i][j]=dpStr[i-1][j-1]+charA[i];
				}
			}
		}
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (dp[i][j]==dp[n-1][m-1]) {
					System.out.println(dpStr[i][j]);
				}
			}
		}
		return dp[n-1][m-1];
	}

}
可以打印出来最长的子串哦!

package com.example.oj;
public class 动态规划之最长公共子序列 {
	public static void main(String[] args) {
		//保留空字符串是为了getLength()方法的完整性也可以不保留  
	    //但是在getLength()方法里面必须额外的初始化c[][]第一个行第一列  
		String x="ABCBDAB";
		String y="ABCBDAB";
	    int [][] b=getLength(x,y);
	    getMaxLenString(b,x,y);
	}

    private static void getMaxLenString(int[][] dp, String x, String y) {
		String res="";
		int startX=x.length();
		int startY=y.length();
		while (startX>=1&&startY>=1) {
			if (dp[startX][startY]==dp[startX-1][startY-1]+1) {
				res=x.charAt(startX-1)+res;
				startX--;
				startY--;
			}else if (dp[startX][startY]==dp[startX-1][startY]) {
				startX--;
			}else if (dp[startX][startY]==dp[startX][startY-1]) {
				startY--;
			}
		}
		System.out.println(res);
	}

	private static int[][] getLength(String x, String y) {
    	char[] charX = x.toCharArray();
    	char[] charY = y.toCharArray();
    	//dp[i][j]表示以char[0--i-1]和char[0--j-1]最长公共子序列
    	//dp[0][0]表示两个都是空串,直接为0;
    	int dp[][]=new int[charX.length+1][charY.length+1];
    	for (int i = 0; i <=charX.length; i++) {
        		dp[i][0]=0;
		}
    	for (int i = 0; i <=charY.length; i++) {
    			dp[0][i]=0;
		}
    	for (int i =1; i <=charX.length; i++) {
			for (int j = 1; j <=charY.length; j++) {
				if (charX[i-1]==charY[j-1]) {
					dp[i][j]=dp[i-1][j-1]+1;
				}else {
					dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
				}
			}
		}
    	System.out.println(dp[charX.length][charY.length]);
		return dp;
	}
}
回溯法输入最长的子序列!

还有一个是博弈问题:

public class 动态规划之博弈问题 {
	//递归版本
	public int  win(int [] arr) {
		if (arr==null||arr.length==0) {
			return 0;
		}
		return Math.max(f(arr,0,arr.length-1), s(arr,0,arr.length-1));
	}
    //后拿情况下的最大值
	private int s(int[] arr, int i, int j) {
		if (i==j) {
			return 0;
		}
		return Math.min(f(arr, i+1, j), f(arr, i, j-1));
	}
	//从 i 到j情况下拿到的值的最大值;
    //先拿情况下,等拿完之后就会变为后拿情况
	private int f(int[] arr, int i, int j) {
		if (i==j) {
			return arr[i];
		}
		//返回从i+1到j后拿情况+arr[i]和从i到j-1后拿情况下+arr[j]的两者取最大值就可以了
		return Math.max(arr[i]+s(arr, i+1, j), arr[j]+s(arr, i, j-1));
	}
	
	
	//动态规划版本
	public int  win2(int[] arr) {
		if (arr==null||arr.length==0) {
			return 0;
		}
		//首选从i-j中选出来的最大值
		int[][] f=new int[arr.length][arr.length];
		//次选从i-j选出来的最大值
		int[][] s=new int[arr.length][arr.length];
	    for (int j = 0; j < arr.length; j++) {
	    	//只有首选能选到的情况
			f[j][j]=arr[j];
			for (int i = j-1; i>=0; i--) {
				f[i][j]=Math.max(arr[i]+s[i+1][j], arr[j]+s[i][j-1]);
				s[i][j]=Math.min(f[i+1][j], f[i][j-1]);
			}
		}	
	    return Math.max(f[0][arr.length-1], s[0][arr.length-1]);
	}
	
	
	

}
好了,目前碰到过的DP就这么多了,说多不多,说少还真不少哎。。。




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值