1. 程式人生 > >演算法導論-第15章-動態規劃-15-2 最長迴文子序列(LPS)

演算法導論-第15章-動態規劃-15-2 最長迴文子序列(LPS)

問題描述

迴文序列(Palindromic sequence, Palindrome)是指正向遍歷和反向遍歷完全相同的序列,例如字串“AAAAA”顯然是一個迴文序列,又如字串“[email protected]”也是一個迴文序列。現在,我們要在一個(字元)序列中找出最長迴文子序列的長度。例如字元序列"BBABCBCAB",最長迴文子序列是“BACBCAB”(可能不唯一),它的長度是7;子序列"BBBBB"和"BBABB"雖然也是迴文序列,但卻不是最長的,因此不合題意。

分析

對任意字串,如果頭和尾相同,那麼它的最長迴文子序列一定是去頭去尾之後的部分的最長迴文子序列加上頭和尾。如果頭和尾不同,那麼它的最長迴文子序列是去頭的部分的最長迴文子序列和去尾的部分的最長迴文子序列的較長的那一個。 設字串為s,f(i,j)表示s[i..j]的最長迴文子序列。  狀態轉移方程如下:  當i>j時,f(i,j)=0。  當i=j時,f(i,j)=1。  當i<j並且s[i]=s[j]時,f(i,j)=f(i+1,j-1)+2。  當i<j並且s[i]≠s[j]時,f(i,j)=max( f(i,j-1), f(i+1,j) )。  由於f(i,j)依賴i+1,所以迴圈計算的時候,第一維必須倒過來計算,從s.length()-1到0。  最後,s的最長迴文子序列長度為f(0, s.length()-1)。

以"BBABCBCAB"為例:
(注:本程式的填表方向斜向左上,即從最後一行的最後開始到第一行最後一位)

程式碼

(時間複雜度O(n^2)),空間複雜度O(n^2))
#include <iostream>  
#include <cstring>  
using namespace std;  

#define MAX 100  
#define max(a,b) (a)>(b)?(a):(b)  

int f[MAX][MAX]={0};  

void LPS_Length(char *s,int len)
{
	for (int i=len-1;i>=0;i--)  
	{  
		//	當i=j時,f(i,j)==1
		f[i][i]=1;  
		for (int j=i+1;j<len;j++)
		{
			//	當i<j並且s[i]=s[j]時,f(i,j)=f(i+1,j-1)+2
			if (s[i]==s[j])			
				f[i][j]=f[i+1][j-1]+2;
			else		
				//	當i<j並且s[i]≠s[j]時,f(i,j)=max( f(i,j-1), f(i+1,j) )
				f[i][j]=max(f[i][j-1],f[i+1][j]);  
		}
	}  
	
}
int main()  
{  
		char *str="abcffggcbda";//字串長度不能超過100
		int len=strlen(str);
		LPS_Length(str,len);
		cout<<f[0][len-1]<<endl; //輸出迴文長序列度

	return 0;  
}

為進一步減小空間複雜度,我們發現計算第i行時只用到了第i+1行,這樣我們便不需要n行,只需要2行即可。
起初先在第0行計算f[s.length()-1],然後用第0行的結果計算f[s.length()-2],再用第1行的結果計算f[s.length()-3],以此類推。正在計算的那行設為flag,那麼下一行就是1-flag。這種方法很巧妙。 當計算完成時,如果s.length()是奇數,則結果在第0行;如果是偶數,則結果在第1行。  此空間複雜度為O(n)。
#include <iostream>  
#include <cstring>  
using namespace std;  

#define MAX 100  
#define max(a,b) (a)>(b)?(a):(b)  

int f[2][MAX]={0};  

void LPS_Length(char *s,int len)
{
	int flag=0;
	for (int i=len-1;i>=0;i--)  
	{  
		//	當i=j時,f(i,j)==1
		f[flag][i]=1;  
		for (int j=i+1;j<len;j++)//一個for迴圈是一行,從i到len
		{
			//	當i<j並且s[i]=s[j]時,f(i,j)=f(i+1,j-1)+2
			if (s[i]==s[j])			
				f[flag][j]=f[1-flag][j-1]+2;
			else		
				//	當i<j並且s[i]≠s[j]時,f(i,j)=max( f(i,j-1), f(i+1,j) )
				f[flag][j]=max(f[flag][j-1],f[1-flag][j]);  	
		}
		flag=1-flag;
	}  
	
}
int main()  
{  
		char *str="abcffgtmgcbda";//字串長度不能超過100
		int len=strlen(str);
		LPS_Length(str,len);
		if(len%2 == 0)
			cout<<f[1][len-1]<<endl; //輸出迴文長序列度
		else
			cout<<f[0][len-1]<<endl;

	return 0;  
}

注:此題是求最長迴文子序列,還有類似的題,求最長迴文子串,解法類似:http://blog.csdn.net/u012243115/article/details/41854563

相關推薦

演算法導論-15-動態規劃-15-2 序列LPS

問題描述 迴文序列(Palindromic sequence, Palindrome)是指正向遍歷和反向遍歷完全相同的序列,例如字串“AAAAA”顯然是一個迴文序列,又如字串“[email 

演算法導論——動態規劃公共序列LCS序列LPS

有兩個字串A和B,假設為A=”abcbdab”,B=”bdcaba”;最長公共子序列(LCS)問題指的時找到A和B的一個公共的子串C,C的長度要是最長。 在這裡我們很明顯的發現最長子序列為”bcba” 用動態規劃的思想來考慮這個問題: 若A={a1,a2,

Longest Palindromic Substring動態規劃之尋找序列

求一個字串中符合迴文性質的最長子序列Example:Input: "babad" Output: "bab" Note: "aba" is also a valid answer. Example:Input: "cbbd" Output: "bb"演算法思路:一開始的

動態規劃1.求

求字串的子串大致有四中方法,暴力,DP,中心拓展,馬拉車演算法,這篇講DP怎麼做。 DP最重要的就是要能利用到前面的結果來推斷當前狀態,比暴力優化的地方就在此,暴力需要對每一個字串做一次O(n)的操作才能判斷出結果,也就是整個過程要O(n^3),但DP對每一個字串的判斷時間是O(1),總共是O(n^2)

公共序列LCS和序列動態規劃演算法

c[i][j] 用來表示 x[i] 和y[j] 的LCS 長度 對c[i][j], 若i = 0或j = 0,則c[i][j] = 0, 兩個原序列有一個為空,則沒有LCS; 若i,j > 0 且x[i] = y[j],則c[i][j] = c[i-1][j-1] +

動態規劃串 & 序列

一、題目 所謂迴文字串,就是一個字串,從左到右讀和從右到左讀是完全一樣的,比如 “a”、“aba”、“abba”。 對於一個字串,其子串是指連續的一段子字串,而子序列是可以非連續的一段子字串。 最長迴文子串 和 最長迴文子序列(Longest Palindrom

動態規劃1.求

一個 不回 art start ref 規劃 r+ 子串 for 求字符串的子串大致有四中方法,暴力,DP,中心拓展,馬拉車算法,這篇講DP怎麽做。 DP最重要的就是要能利用到前面的結果來推斷當前狀態,比暴力優化的地方就在此,暴力需要對每一個字符串做一次O(n)的操作才能判

leetcode5. 動態規劃

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。 示例 1: 輸入: "babad" 輸出: "bab" 注意: "aba"也是一個有效答案。 示例 2: 輸入: "cbbd" 輸出: "bb" 解題思路: 採用動態規劃的

動態規劃例題:不下降序列c序列

問題:在一個數字序列中,找到最長的子序列(可以不連續),使得這個子序列是不下降(非遞減)的。求出此序列的長度。輸入:8          1 2 3 -9 3 9 0 11輸出:6         (即:1  2  3  3  9  11)解:public class Mai

動態規劃和遞

給一個字串,找出它的最長的迴文子序列的長度。例如,如果給定的序列是“BBABCBCAB”,則輸出應該是7,“BABCBAB”是在它的最長迴文子序列。 “BBBBB”和“BBCBB”也都是該字串的迴文子序列,但不是最長的。注意和最長迴文子串的區別(參考:最長迴文串)!這

動態規劃序列

題目 找出字串中最長迴文子序列,可以在原字串中不連續。 如“character”的最長迴文子序列為“carac”。 分析1 設字串s從第i個字元到第j個字元的最長迴文子序列長度為p[i,j],則

leetcode演算法題—golang—題5

題目:最長迴文子串 給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。 示例 1: 輸入: "babad" 輸出: "bab" 注意: "aba"也是一個有效答案。 示例 2: 輸入: "cbb

演算法題:C#實現

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為 1000。 示例 1: 輸入: "babad" 輸出: "bab" 注意: "aba" 也是一個有效答案。 示例 2: 輸入: "cbbd" 輸出: "bb

LeetCode五題:C語言

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。 示例 1: 輸入: “babad” 輸出: “bab” 注意: "aba"也是一個有效答案。 示例 2: 輸入: “cbbd” 輸出: “bb” 解法一:暴力求解法 思想:

Manacher演算法------求Java)

最長迴文子串 對於一個字串,請設計一個高效演算法,計算其中最長迴文子串的長度。 給定字串A以及它的長度n,請返回最長迴文子串的長度。 測試樣例: "abc1234321ab",12 返回:7 public class Main {      public st

13屆景馳-埃森哲杯廣東工業大學ACM程式設計大賽 D psd面試(序列,區間dp)

題目描述 掌握未來命運的女神 psd 師兄在拿了朝田詩乃的 buff 後決定去實習。 埃森哲公司註冊成立於愛爾蘭,是一家全球領先的專業服務公司,為客戶提供戰略、諮詢、數字、技術和運營服務及

經典演算法——序列

最長迴文子序列LPS(Longest Palindromic Subsequence)問題 一個字串有許多子序列,比如字串cabbeaf,它的子序列有c、abb、e、a、f,可以通過刪除某些字元而變

演算法導論-15-動態規劃-15.1 鋼條切割問題

一、綜述 動態規劃是通過組合子問題的解而解決整個問題的。 動態規劃對每個子問題只求解一次,將其結果儲存在一張表中。動態規劃通常用於最優化問題。動態規劃的設計步驟:a. 描述最優解的結構b. 遞迴定義最優解的值c. 按自底向上的方式計算最優解的值d. 由計算出的資訊構

強化學習導論 動態規劃

  這一篇來講一下第四章,動態規劃。 DP這個詞,指的是一系列的演算法,這些演算法主要用來解決:當我有了一個可以完美模擬馬爾可夫過程的模型之後,如何計算最優policies的問題。注意是policies,表明最優的策略可能不止一個。經典的DP演算法在強化學習中的應用受限的原因有兩

演算法導論 三版 動態規劃之庫存規劃

15-11 題目:某公司的額定產能是每月生產m臺裝置,而如果每月生產超過m臺,則需要額外僱傭勞動力,每多生產一臺裝置所需的僱傭成本為c。已知未來n個月每個月的需求為d[i],不同的月份需求不一樣,但是具體到某個月需求是確定的。另外,如果每個月末有裝置剩餘,則需要付出h(j)