動態規劃解最長迴文子序列並優化空間複雜度
版權所有。所有權利保留。
歡迎轉載,轉載時請註明出處:
http://blog.csdn.net/xiaofei_it/article/details/16813591
一個字串有許多子序列,比如字串abcfgbda,它的子序列有a、bfg、bfgbd,在這些子序列中肯定有迴文字串。現在要對任意字串求其最長的迴文子序列。注意,本文不是解決最長迴文子串,迴文子串是連續的,迴文子序列是不連續的。
字串abcfgbda的最長迴文子序列為abcba,長度為5。
輸入:包含若干行,每行有一個字串,字串由大小寫字母構成,長度不超過100。
輸出:對每個輸入,輸出一行,該行有一個整數,表示最長迴文子序列的長度。
Example
Input:
a
abcfgbda
Output:
1
5
該題採用動態規劃思想。
對任意字串,如果頭和尾相同,那麼它的最長迴文子序列一定是去頭去尾之後的部分的最長迴文子序列加上頭和尾。如果頭和尾不同,那麼它的最長迴文子序列是去頭的部分的最長迴文子序列和去尾的部分的最長迴文子序列的較長的那一個。
設字串為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) )。
注意如果i+1=j並且s[i]=s[j]時,f(i,j)=f(i+1,j-1)+2=f(j,j-1)+2=2,這就是“當i>j時f(i,j)=0”的好處。
由於f(i,j)依賴i+1,所以迴圈計算的時候,第一維必須倒過來計算,從s.length()-1到0。
最後,s的最長迴文子序列長度為f(0, s.length()-1)。
程式碼如下:
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 101
#define max(a,b) (a)>(b)?(a):(b)
int main()
{
string s;
while (cin>>s)
{
int f[MAX][MAX];
memset(f,0,sizeof(f));
for (int i=s.length()-1;i>=0;i--)
{
f[i][i]=1;
for (int j=i+1;j<s.length();j++)
if (s[i]==s[j])
f[i][j]=f[i+1][j-1]+2;
else
f[i][j]=max(f[i][j-1],f[i+1][j]);
}
cout<<f[0][s.length()-1]<<endl;
}
return 0;
}
空間複雜度為O(n^2)。
進一步減少記憶體使用,我們發現計算第i行時只用到了第i+1行,這樣我們便不需要n行,只需要2行即可。
起初先在第0行計算f[s.length()-1],然後用第0行的結果在第1行計算f[s.length()-2],再用第1行的結果在第0行計算f[s.length()-3],以此類推。正在計算的那行設為now,那麼計算第now行時,就要用第1-now行的結果。這種方法很巧妙。
當計算完成時,如果s.length()是奇數,則結果在第0行;如果是偶數,則結果在第1行。
此空間複雜度為O(n)。
程式碼如下:
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 101
#define max(a,b) (a)>(b)?(a):(b)
int main()
{
string s;
while (cin>>s)
{
int f[2][MAX];
memset(f,0,sizeof(f));
int now=0;
for (int i=s.length()-1;i>=0;i--)
{
f[now][i]=1;
for (int j=i+1;j<s.length();j++)
if (s[i]==s[j])
f[now][j]=f[1-now][j-1]+2;
else
f[now][j]=max(f[now][j-1],f[1-now][j]);
now=1-now;
}
if (s.length()%2==0)
cout<<f[1][s.length()-1]<<endl;
else
cout<<f[0][s.length()-1]<<endl;
}
return 0;
}
相關文章
- [動態規劃] 六、最長迴文子串動態規劃
- 動態規劃:最長上升子序列動態規劃
- 最長上升子序列動態規劃動態規劃
- 動態規劃-最長公共子序列動態規劃
- 動態規劃——最長公共子序列動態規劃
- 最長公共子序列&迴文字串 nyoj動態規劃字串動態規劃
- 動態規劃-最長上升子序列模型動態規劃模型
- 動態規劃(最長公共子序列LCS)動態規劃
- 動態規劃7:最長上升子序列LIS動態規劃
- 詳解動態規劃最長公共子序列--JavaScript實現動態規劃JavaScript
- 動態規劃求解最長上升子序列問題動態規劃
- 最長公共子序列問題—動態規劃sdut動態規劃
- 【LeetCode動態規劃#14】子序列系列題(最長遞增子序列、最長連續遞增序列、最長重複子陣列、最長公共子序列)LeetCode動態規劃陣列
- 動態規劃經典問題----最長公共子序列動態規劃
- 動態規劃求最長降序序列動態規劃
- 力扣1143. 最長公共子序列 動態規劃之最長公共子序列力扣動態規劃
- 01揹包動態規劃空間優化動態規劃優化
- 動態規劃之最長公共子序列求解動態規劃
- 北京大學郭煒-最長上升子序列 動態規劃講解動態規劃
- 多重揹包動態規劃及空間優化動態規劃優化
- [演算法筆記]動態規劃之最長公共子串和最長公共子序列演算法筆記動態規劃
- 時間複雜度跟空間複雜度時間複雜度
- 時間複雜度和空間複雜度時間複雜度
- 時間複雜度與空間複雜度時間複雜度
- 最詳細的解說—時間和空間複雜度複雜度
- 以最長公共子序列問題理解動態規劃演算法(DP)動態規劃演算法
- “最長公共字串子序列”問題的動態規劃法演算法字串動態規劃演算法
- lc1771 由子序列構造的最長迴文串的長度
- 淺談最長公共子序列引發的經典動態規劃問題動態規劃
- 時間複雜度O(n)和空間複雜度時間複雜度
- 時間複雜度和空間複雜度 順序時間複雜度
- 動態規劃---求硬幣最優解動態規劃
- LeetCode516. 最長迴文子序列LeetCode
- 關於計算時間複雜度和空間複雜度時間複雜度
- 【資料結構】-時間複雜度和空間複雜度資料結構時間複雜度
- 那些年忽略的知識:時間複雜度和空間複雜度詳解時間複雜度
- java 最長迴文子串Java
- 122 演算法的時間複雜度和空間複雜度詳解演算法時間複雜度