【DP】 最长公共回文子序列

问题描述:
给一个字符串,找出它的最长的回文子序列的长度。例如,如果给定的序列是“BBABCBCAB”,则输出应该是7,“BABCBAB”是在它的最长回文子序列。 “BBBBB”和“BBCBB”也都是该字符串的回文子序列,但不是最长的。


1)最优子结构

假设 X[0 ... n-1]  是给定的序列,长度为n.  让 L(0,n-1) 表示 序列 X[0 ... n-1] 的最长回文子序列的长度。

1. 如果X的最后一个元素和第一个元素是相同的,这时:L(0, n-1) = L(1, n-2) + 2 ,  还以 “BBABCBCAB” 为例,第一个和最后一个相同,因此 L(1,n-2) 就表示蓝色的部分。

2. 如果不相同:L(0, n-1) = MAX ( L(1, n-1) ,  L(0, n-2) )。 以”BABCBCA” 为例,L(1,n-1)即为去掉第一个元素的子序列,L(0, n-2)为去掉最后一个元素。




package 最长回文子序列;

import java.util.Scanner;

public class test {

	/**
	 * 计算个数的时候,比较适合自上而下计算;
	 * 但是求解具体的值,适合自下而上。
	 */
	//统计个数
//	public static int lhc(int start,int end){
//		if(start>=end)
//			return 0;
//		else{
//			if(ch[start]==ch[end]){
//				//他们之间最长子序列的长度加2
//				return 	lhc(start+1,end-1)+2;
//			}else{
//				//判断是[start+1,end],[start,end-1]之间的序列长度
//				return lhc(start+1,end)>lhc(start,end-1)?lhc(start+1,end):lhc(start,end-1);
//			}
//		}
//	}
	public void inti(int[][] lpsArray,int max){
		for(int i=0;i<max;i++)
			for(int j=0;j<max;j++)
				lpsArray[i][j]=0;
	}
	
	public int max(int x,int y){
		return x>y?x:y;
	}
	
	public char dir(int x,int y){
		return x>y?'←':'↓';
	}
	//创建数组
	public int[][] lps(char[] ch){
		int[][] lpsArray = new int[ch.length][ch.length];
		char[][] dirc = new char[ch.length+1][ch.length+1];
		this.inti(lpsArray,ch.length);
		//method 1.
		/*
		
		for(int i=0;i<ch.length;i++)
			for(int j=i;j<ch.length;j++){
				if(i==j)
					lpsArray[i][j]=0;
				else{
					if(ch[i]==ch[j])
						lpsArray[i][j]=1;
					else
						lpsArray[i][j]=0;
				}
			}
		*/
		//method 2.
		for(int i=0;i<ch.length;i++)
			lpsArray[i][i]=0;
		
		for(int i=1;i<ch.length;i++){
			int temp =0;
			//开始计算ch[i]到ch[j]之间最长回文的个数
			for(int j=0;j+i<ch.length;j++){
				if(ch[j]==ch[j+i]){
						temp = lpsArray[j+1][j+i-1]+2;
						dirc[j][j+i]='√';
				}else{
						temp = max(lpsArray[j][i+j-1],lpsArray[j+1][j+i]);
						dirc[j][j+i] = dir(lpsArray[j][i+j-1],lpsArray[j+1][j+i]);
				}
				lpsArray[j][i+j]=temp;
			}
		}
		for(int i=0;i<ch.length;i++){
			for(int j =0;j<ch.length;j++)
				System.out.print(" "+dirc[i][j]+"  ");
			System.out.println();
		}
		this.showSeq(dirc,lpsArray,ch.length);
		return lpsArray;
	}
	
	//输出序列
	public void showSeq(char[][] dirc,int[][] lpsArray,int max){
		 int i = 0;  int j = max-1;
		 while(lpsArray[i][j]!=0){
			 System.out.println(dirc[i][j]);
			 if(dirc[i][j]=='←'){
				 j--;
			 }else if(dirc[i][j]=='↓'){
				 i++;
			 }else{
				 System.out.println("i = "+i+" j="+j);
				 i++;
				 j--;
			 }
		 }
	}
	//正
	public static void main(String[] args) {
		test t = new test();
		// TODO Auto-generated method stub
		System.out.println("请输入任意的字符串");
		Scanner s =  new Scanner(System.in);
		String str = s.next();
		//将字符串变为char数组
		char[] ch = new char[str.length()] ;
		str.getChars(0, str.length(), ch,0);
		//存储最优解
		int[][] lps =t.lps(ch);
		
		for(int i=0;i<ch.length;i++){
			for(int j =0;j<ch.length;j++)
				System.out.print(lps[i][j]+"  ");
			System.out.println();
		}	
	}

}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值