Algorithm 最长公共子串的DP记忆化方法

Algorithm 最长公共子串的DP记忆化方法,algorithm,dynamic-programming,Algorithm,Dynamic Programming,有人能提供两个字符串之间最长公共子字符串的记忆方法吗?我知道最底层的解决方案,但我不能自上而下地思考。 预期时间复杂度-O(n^2)记忆是指缓存子问题的解决方案,以便以后使用。在最长公共子序列问题中,您尝试匹配两个子序列的子字符串,以查看它们是否匹配,并在内存中保留找到的最长子序列。以下是您正在寻找的Java解决方案(LCS的记忆版): 公共类最长公共子序列{ 私有静态HashMap缓存=新HashMap(); 私有静态整数计数=0,总计=0; 公用静态空干管(字符串SARG[]){ 扫描仪=新

有人能提供两个字符串之间最长公共子字符串的记忆方法吗?我知道最底层的解决方案,但我不能自上而下地思考。
预期时间复杂度-O(n^2)

记忆是指缓存子问题的解决方案,以便以后使用。在最长公共子序列问题中,您尝试匹配两个子序列的子字符串,以查看它们是否匹配,并在内存中保留找到的最长子序列。以下是您正在寻找的Java解决方案(LCS的记忆版):

公共类最长公共子序列{
私有静态HashMap缓存=新HashMap();
私有静态整数计数=0,总计=0;
公用静态空干管(字符串SARG[]){
扫描仪=新的扫描仪(System.in);
字符串x=scanner.nextLine();
字符串y=scanner.nextLine();
int max=0;
字符串最长=”;

对于(int j=0;j而言,使用递归的记忆使用自顶向下的方法。 下面以使用科曼公司DP的LCS为例,是描述其工作原理的伪代码

MEMOIZED-LCS-LENGTH(X,Y)
 m<-length[X]
 n<-length[Y]
for(i<-1 to m)
  do for(j<-1 to n)
        c[i,j]<- -1

for(i<-1 to m)
    c[i,0]<-0
for(j<-1 to n)
    c[0,j]<-0
return RECURSIVE-LCS-LENGTH(X,Y,1,1)


RECURSIVE-LCS-LENGTH(X,Y,i,j)
if(c[i,j]!=-1) 
  return c[i,j]
//Above 2 line fetches the result if already present, instead of computing it again.
if(x[i]==y[j]) 
  then c[i,j]<-RECURSIVE-LCS-LENGTH(X,Y,i+1,j+1)+1 
else 
     c1<- RECURSIVE-LCS-LENGTH(X,Y,i+1,j)
     c2<-RECURSIVE-LCS-LENGTH(X,Y,i,j+1)
       if(c1<c2)
         then c[i,j]<-c1
       else c[i,j]<-c2

return c[i,j]
MEMOIZED-LCS-LENGTH(X,Y)

m自上而下的方法

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

string X, Y;             //input strings
int ans, dp[105][105];   // ans : answer

int LCS(int n, int m)    //our function return value of (n,m) state
{                        // so that we can use the result in (n+1,m+1) state
  if(n == 0 || m == 0) return 0;   //in case of match in (n+1,m+1) state
  if(dp[n][m] != -1) return dp[n][m];

  LCS(n-1,m);          //to visit all n*m states          (try example:  X:ASDF
  LCS(n,m-1);          // we call these states first                     Y:ASDFF)

  if(X[n-1] == Y[m-1])
  {

    dp[n][m] =  LCS(n-1,m-1) + 1;
    ans = max(ans, dp[n][m]);
    return dp[n][m];
  }
    return dp[n][m] = 0;
}

int main()
{
    int t; cin>>t;
    while(t--)
    {
      int n, m; cin>>n>>m;  //length of strings
      cin>>X>>Y;
      memset(dp, -1, sizeof dp);
      ans = 0;
      LCS(n, m);
      cout<<ans<<'\n';
    }
    return 0;
}
#包括
#包括
#包括
使用名称空间std;
字符串X,Y;//输入字符串
int ans,dp[105][105];//ans:回答
int LCS(int n,int m)//我们的函数返回(n,m)状态的值
{//这样我们就可以在(n+1,m+1)状态下使用结果
如果(n==0 | | m==0)在(n+1,m+1)状态下匹配,则返回0;//如果匹配
如果(dp[n][m]!=-1)返回dp[n][m];
LCS(n-1,m);//访问所有n*m个状态(尝试示例:X:ASDF
LCS(n,m-1);//我们首先称这些状态为Y:ASDFF)
如果(X[n-1]==Y[m-1])
{
dp[n][m]=LCS(n-1,m-1)+1;
ans=最大值(ans,dp[n][m]);
返回dp[n][m];
}
返回dp[n][m]=0;
}
int main()
{
int t;cin>>t;
而(t--)
{
int n,m;cin>>n>>m;//字符串的长度
cin>>X>>Y;
膜组(dp,-1,dp大小);
ans=0;
LCS(n,m);

cout下面描述了一个简单的解决方案。此处
memo[n][m]
不存储 最大子字符串,但您可以将最大子字符串存储在pointer maxi中,如下所示:

 #include<iostream>
 #include<string>
 using namespace std;
 int lcs(string X,string Y,int n,int m,int *maxi,int memo[][8]) {


if(n==0||m==0) {

return 0;
}
int k=0;
int j=0;

if(memo[n-1][m-1]!=-1) {
return memo[n-1][m-1];
}
if(X[n-1]==Y[m-1]) {

memo[n-1][m-1] =  1+lcs(X,Y,n-1,m-1,maxi,memo);
if(*maxi<memo[n-1][m-1]) 
*maxi=memo[n-1][m-1];

}
else {
memo[n-1][m-1]=0;
}


int l =  lcs(X,Y,n-1,m,maxi,memo);
int i = lcs(X,Y,n,m-1,maxi,memo);

return memo[n-1][m-1];



}

int main() 
{ 
int n,m; 

string X = "abcdxyze"; 
//string X = "abcd";
string Y = "xyzabcde"; 

 n=X.length(); 
 m=Y.length(); 
 int memo[n][8];
 for(int i=0;i<n;i++) {
  for(int j=0;j<m;j++) {
  memo[i][j]=-1;
  }
 }
 int maxi=0;
 int k = lcs(X,Y,n,m,&maxi,memo); 
 cout << maxi;
  return 0; 
 } 
#包括
#包括
使用名称空间std;
int lcs(字符串X、字符串Y、int n、int m、int*maxi、int memo[][8]){
如果(n==0 | | m==0){
返回0;
}
int k=0;
int j=0;
如果(备忘录[n-1][m-1]!=-1){
返回备忘录[n-1][m-1];
}
如果(X[n-1]==Y[m-1]){
备忘录[n-1][m-1]=1+lcs(X,Y,n-1,m-1,最大,备忘录);

if(*maxi递归加上python中的记忆。请注意,这段代码在Hackerearth和Geeksforgeks上部分被接受。对于更大的测试用例,它给出了MLE

import sys
sys.setrecursionlimit(1000000)
maxlen=0
t=None
def solve(s1, s2, n, m):
   global maxlen, t
   if n<=0 or m<=0:
       return 0
   if t[n][m]!=-1:
       return t[n][m]
   if s1[n-1]==s2[m-1]:
       temp=1+solve(s1, s2, n-1, m-1)
       maxlen=max(maxlen, temp)
       t[n][m]=temp
       return temp
   t[n][m]=0
   return 0
class Solution:
   def longestCommonSubstr(self, S1, S2, n, m):
       global maxlen, t
       maxlen=0
       t=[[-1]*(m+1) for i in range(n+1)]
       for i in range(n+1):
           for j in range(m+1):
               solve(S1, S2, i, j)
       return maxlen
if __name__=='__main__':
   S1=input().strip()
   S2=input().strip()
   n=len(S1)
   m=len(S2)
   ob = Solution()
   print(ob.longestCommonSubstr(S1, S2, n, m))
导入系统 系统设置递归限制(1000000) maxlen=0 t=无 def解算(s1、s2、n、m): 全局maxlen,t
如果n这里是一个递归的自顶向下的方法:

       public int lcsSubstr(char[] s1, char[] s2, int m, int n, int c) {
            if (m == 0 || n == 0) {
                return c;
            }
            if (s1[m-1] == s2[n-1]) {
                c = lcsSubstr(s1, s2, m-1, n-1, c+1);
            } else {
                c2 = Math.max(lcsSubstr(s1, s2, m, n - 1, 0), lcsSubstr(s1, s2, m-1, n, 0));
            }
            return Math.max(c, c2);
        }

       public int lcsSubstrMemo(char[] s1, char[] s2, int m, int n, int c, int[][] t) {
            if(m == 0 || n == 0) {
                return c;
            }
            if (t[m-1][n-1] != -1) return t[m-1][n-1];
            if(s1[m - 1] == s2[n - 1]) {
                c = lcsSubstr(s1, s2, m - 1, n - 1, c + 1);
            } else {
                c2 = Math.max(lcsSubstr(s1, s2, m, n - 1, 0), lcsSubstr(s1, s2, m - 1, n, 0));
            }
            t[m - 1][n - 1] = Math.max(c, c2);
            return t[m-1][n-1];
        }

伪代码中有一个bug,它应该是
if(c1>c2)
而不是
if(c1
import sys
sys.setrecursionlimit(1000000)
maxlen=0
t=None
def solve(s1, s2, n, m):
   global maxlen, t
   if n<=0 or m<=0:
       return 0
   if t[n][m]!=-1:
       return t[n][m]
   if s1[n-1]==s2[m-1]:
       temp=1+solve(s1, s2, n-1, m-1)
       maxlen=max(maxlen, temp)
       t[n][m]=temp
       return temp
   t[n][m]=0
   return 0
class Solution:
   def longestCommonSubstr(self, S1, S2, n, m):
       global maxlen, t
       maxlen=0
       t=[[-1]*(m+1) for i in range(n+1)]
       for i in range(n+1):
           for j in range(m+1):
               solve(S1, S2, i, j)
       return maxlen
if __name__=='__main__':
   S1=input().strip()
   S2=input().strip()
   n=len(S1)
   m=len(S2)
   ob = Solution()
   print(ob.longestCommonSubstr(S1, S2, n, m))
       public int lcsSubstr(char[] s1, char[] s2, int m, int n, int c) {
            if (m == 0 || n == 0) {
                return c;
            }
            if (s1[m-1] == s2[n-1]) {
                c = lcsSubstr(s1, s2, m-1, n-1, c+1);
            } else {
                c2 = Math.max(lcsSubstr(s1, s2, m, n - 1, 0), lcsSubstr(s1, s2, m-1, n, 0));
            }
            return Math.max(c, c2);
        }

       public int lcsSubstrMemo(char[] s1, char[] s2, int m, int n, int c, int[][] t) {
            if(m == 0 || n == 0) {
                return c;
            }
            if (t[m-1][n-1] != -1) return t[m-1][n-1];
            if(s1[m - 1] == s2[n - 1]) {
                c = lcsSubstr(s1, s2, m - 1, n - 1, c + 1);
            } else {
                c2 = Math.max(lcsSubstr(s1, s2, m, n - 1, 0), lcsSubstr(s1, s2, m - 1, n, 0));
            }
            t[m - 1][n - 1] = Math.max(c, c2);
            return t[m-1][n-1];
        }