算法(八)动态规划----线性动态规划

一、朴素最长非降子序列

1.问题引入

现输入一行数字,要求输出其中最长的非降子序列。
如输入 5 3 4 8 6 7,应输出4;
再如输入3 4 8 6 7,应输出4。

2.思路分析

设dp[i]表示遍历到第i个数时最长子序列的值,首先从第一个数开始,dp[0]=1,这是已知值。之后从i=1开始,逐一与前面的数比较,可设j<i,则如果第i个数大于等于第j个数,dp[i]=dp[j]+1,否则dp[i]=dp[i-1]。对于所有的j,取dp[i]的最大值即可。由此得到状态转移方程dp  [i]= max{dp[j]+1}。

3.代码如下:

<span style="color:#330099">package 动态规划__线性动态规划;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class 朴素最长非降子序列 {
	public static void main(String args[]) throws IOException{
		BufferedReader buf=new BufferedReader(new InputStreamReader(System.in));
		String str=buf.readLine();
		String s[]=str.split(" ");
		int dp[]=new int[s.length];
		dp[0]=1;
		for(int i=1;i<s.length;i++){
			for(int j=0;j<i;j++){
			if(Integer.parseInt(s[i])>=Integer.parseInt(s[j])) 
				dp[i]=Math.max(dp[j]+1, dp[i]);
			else
				dp[i]=dp[i-1];
				}
		}
		System.out.print(dp[s.length-1]);
	}
}</span>


 
二、 方块消除游戏
三、 最长公共序列数问题

1.问题引入:

 

给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。例如,A="1A2C3D4B56”,B="B1D23CA45B6A”,”123456"或者"12C4B6"都是最长公共子序列。给定两个字符串A和B,同时给定两个串的长度n和m,请返回最长公共子序列的长度。保证两串长度均小于等于300。测试样例:第一行输入一个字符串,第二行再输入一个字符串。最后输出最长公共子串的长度。如:1A2C3D4B56

 

B1D23CA45B6A

输出:6

2.思路分析:

设dp[n][m] ,为A的前n个字符与B的前m个字符的公共序列长度,则当A[n]==B[m]的时候,dp[i][j] =
 max(dp[i-1][j-1]+1,dp[i-1][j],dp[i][j-1]),否则,dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);

3.代码如下:
package 动态规划__线性动态规划;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class 最长公共子串 {
	public static void main(String args[]) throws IOException{
		BufferedReader buf=new BufferedReader(new InputStreamReader(System.in));
		String s1=buf.readLine();
		String s2=buf.readLine();
		String s11[]=s1.split("");
		String s21[]=s2.split("");
		int dp[][]=new int[s11.length+1][s21.length+1];
		for(int i=0;i<s11.length;i++)
			dp[i][0]=0;
		for(int j=0;j<s21.length;j++)
			dp[0][j]=0;
				
		for(int i=1;i<=s11.length;i++){
			for(int j=1;j<=s21.length;j++){
				if(s11[i-1].equals(s21[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[s11.length][s21.length]);
	}

}
 
现在如果是要把这个最长公共子序列输出来,可以这样:
public class MaxString {
public static void main(String[] args) {
	String a=max("qwerabcdtyuiop","xcabcdvbn");
	System.out.println(a);
}

public static String max(String s1,String s2){
	String dp[][]=new String[s1.length()+1][s2.length()+1];
	for(int i=0;i<=s1.length();i++){
		for(int j=0;j<=s2.length();j++){
			dp[i][j]="";
		}
	}
	for(int i=0;i<s2.length();i++)
		dp[0][i]="";
	for(int j=0;j<s1.length();j++)
		dp[j][0]="";
	for(int i=1;i<=s1.length();i++){
		for(int j=1;j<=s2.length();j++){
			if(s1.charAt(i-1)==s2.charAt(j-1)){
				dp[i][j]=dp[i-1][j-1]+s1.charAt(i-1);
				
			}else{
				if(dp[i-1][j].length()>dp[i][j-1].length())
					dp[i][j]=dp[i-1][j];
				else
					dp[i][j]=dp[i][j-1];
			}
		}
	}
	return dp[s1.length()][s2.length()];
}
}

 
再看一个相似的例子:构造回文数问题,现输入一个字符串,则至少删除几个元素可以使这个字符串成为一个回文字符串,输出这个最小值。这题也可以转化为最长公共子序列问题,我们把原字符串逆序得到一个新的字符串,求出这两个字符串的最长公共子序列长度,再用原字符串的长度减去这个 最长公共子序列的长度即为所求值。
代码如下:
package 动态规划;  
  
import java.util.Scanner;  
  
public class 构造回文字符串 {  
    public static void main(String args[]){  
        String str=new Scanner(System.in).nextLine();  
        int max=Hui(str,str.length());  
        System.out.println(max);  
    }  
    public static int Hui(String str,int len){  
        String rev=new StringBuffer(str).reverse().toString();  
        int dp[][]=new int[len+1][len+1];  
        for(int i=0;i<len+1;i++ ) dp[i][0]=dp[0][1]=0;  
        for(int i=1;i<=len;i++){  
            for(int j=1;j<=len;j++){  
                if(str.charAt(i-1)==rev.charAt(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]);  
            }  
        }  
        int max=dp[len][len];//最大匹配数  
        return len-max;  
    }  
  
}


 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w_t_y_y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值