之前漏了一题是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背包问题,例如华为机试题: 购物单--链接:
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就这么多了,说多不多,说少还真不少哎。。。