題目:給定兩個字符串,求兩個字符串最長連續字符串的數目。比如:query爲“acbac”,text爲“acaccbabb”,那麼最長的連續子序列爲“cba”,輸出3。請注意程序效率。
題目解析:
一開始看到這個題,可能會想到最長公共子序列的方法,其實是不對的。因爲這裏要求必須連續,而最長公共子序列爲不連續的。狀態轉移方程不對。
方案一:暴力求法
可以分別將query的第0位到第n-1位爲起始字符串,在text中遍歷,尋找最長的子串。
時間複雜度較高O(m*n).
方案二:動態規劃
這裏很不容易想到動態規劃,dp[i][j]這麼和dp[i-1][j]/dp[i][j-1]/dp[i-1][j-1]尋找關係?不能隨便刪掉一個字符。
這裏就需要思維的擴展了,當j+1時,dp[i][j+1] 和dp[i][j]什麼關係呢?也就是j序列多了一個字符,要麼不影響最大長度,dp[i][j+1] = dp[i][j]; 要麼第j+1個字符結尾的長度變大。那麼就需要以j+1結尾的字符,在0.....i之間遍歷。找到最大長度。
根據這個思路,就能寫出動態規劃算法。
#include <iostream>
using namespace std;
int TailLengh(string test,int pos1,string goal,int pos2){
int i = pos1,j = pos2,end = j;
int mark,temp = 0;
int max = 0;
while(i>=0){
if(test[i] == goal[j]){
temp = 0;
mark = i;
while(i>=0 && j >=0 && test[i--] == goal[j--])
++temp;
if(j<0)
return temp;
if(temp > max)
max = temp;
i = mark;
j = end;
}
--i;
}
return max;
}
int FindLongest(string test,string goal){
if(test.size() == 0 || goal.size() == 0)
return 0;
int len_t = test.size();
int len_g = goal.size();
int **dp = new int*[len_t+1];
for(int i =0;i <= len_t;i++)
dp[i] = new int[len_g+1];
for(int i = 0;i <= len_t;i++)
dp[i][0] = 0;
for(int j = 0;j <= len_g;j++)
dp[0][j] = 0;
for(int i = 1;i <= len_t;i++){
for(int j = 1;j <= len_g;j++){
int temp = TailLengh(test,i-1,goal,j-1);
dp[i][j] = temp > dp[i][j-1] ? temp : dp[i][j-1];
}
}
int res = dp[len_t][len_g];
for(int i = 0;i <= len_t;i++)
delete []dp[i];
delete []dp;
return res;
}
int main()
{
string test = "sdfasdfadsffortqest";
string goal = "ccsdfasdfadsffortquery";
cout << FindLongest(test,goal) << endl;
return 0;
}