最长公共子串

简介: 最长公共子串

 👉引言💎


铭记于心
🎉✨🎉我唯一知道的,便是我一无所知🎉✨🎉


💎求解最长公共子串


既然我们已经知道最长公共子序列的解法,那么相应地子串解法是不是也迎刃而解了呢? 首先,子串与子序列什么区别呢? 这里我要声明一下,有些题解将子串与子序列混为一谈,标题为子串,但其实求解的是子序列,这其实是不对的,子串是连续的,而子序列既可以连续也可以不连续,只要字符串里顺序包含序列里的字符即可。 还记得求解子序列时我们是怎样列出条件,从记忆化搜索到动态规划的吗?

没错,就是看有哪些情况与假设,对于子序列来说,就是

1.str1[i]与str2[j]相同时,此时寻找process(i-1,j-1),然后+1

2.str1[i]与str2[j]不同时,此时有两种情况: process(i,j-1) or process(i-1,j)

然后取max,如果要记录路径的话,也就是存在多个解取最优时,就需要再记录一下 方向,以便于推导路线

那么,对于 子串呢?因为必须连续,所以 当str1[i]与str2[j]相同时,去寻找上面三种情况;当不相同时,则该i处字符就不算了(必须连续),直接递归寻找 以i-1或j-1位置的字符结尾的字符串 的子串


👉记忆化搜索


int process(string& str1, string& str2, int i, int j) {//以i,j为结尾下标
  if (dp[i][j])//如果该位置的答案已经被求解出来,那么直接返回答案
  {
    return dp[i][j];
  }
  if (i == 0 || j == 0) {//分析各种边界条件(当两字符串其中一个或者都只剩下一个字符时,分析两者相等与不等的情况),找递归出口
    if (str1[i] == str2[j]) {
      dp[i][j] = 1;
    }
    return dp[i][j];
  }
  int p3 = 0, p1 = 0, p2 = 0;
  if (str1[i] == str2[j]) {
    p1 = process(str1, str2, i, j - 1);//找该位置的最大值
    p2 = process(str1, str2, i - 1, j);
    p3 = process(str1, str2, i - 1, j - 1) + 1;
  }
  else
  {
    process(str1, str2, i, j - 1);
    process(str1, str2, i - 1, j);
  }
  dp[i][j] = max(p1, max(p2, p3));//其实如果不求具体值,递归里面就可以去找最大值,但是因为要找i,j下标,所以最后去遍历dp表
  return dp[i][j];
}
int longestCommonSubsequence(string text1, string text2) {
  dp.resize(text1.size(), vector<int>(text2.size())); flag.resize(text1.size(), vector<int>(text2.size()));
  int ana = process(text1, text2, text1.size() - 1, text2.size() - 1);
  return ana;
}
int main() {
longestCommonSubsequence("WOAINIyishengyishi", "WOAINI") ;
  for (vector<int>t : dp) {
    for (int i : t)cout << i << " ";
    cout << endl;
  }
  return 0;
}

image.png

子串的路径输出更加简单,我们不需要再去建立数组,而只需要找到dp表里最大值的下标,然后通过长度倒推即可请往下看


👉动态规划


int main() {
  string s1 = "yongwangzhiqian", s2 = "yong"; int len1 = s1.size(), len2 = s2.size();
  vector<vector<int>>dp(len1 + 1, vector<int>(len2 + 1));
  int max = 0, path1 = 0, path2 = 0;
  for (int i = 1; i <= len1; i++) {
    for (int j = 1; j <= len2; j++) {
      if (s1[i - 1] == s2[j - 1])
      {//int t=max(dp[i][j-1],dp[i-1][j]);如果直接改是这样的,但是优化一下就是如下了
        dp[i][j] = dp[i - 1][j - 1] + 1;// dp[i][j] = max(dp[i - 1][j - 1] + 1,t);
        if (dp[i][j] > max) {
          max = dp[i][j];
          path1 = i - 1; path2 = j - 1;//得到下标
        }
      }
    }
  }
  cout << max << " " << path1 << " " << path2 << endl; string ans((s1.begin() + path1 + 1 - max), (s1.begin() + path1 + 1));
  cout << ans << endl;//左闭右开,末尾取不到,所以加1
  return 0;
}

image.png

🌹写在最后💖: 路漫漫其修远兮,吾将上下而求索!伙伴们,明天见!🌹🌹🌹


相关文章
|
5月前
|
人工智能 算法
最长公共子串
最长公共子串
47 2
|
5月前
|
Java
5.最长回文子串
5.最长回文子串
|
Shell
【Leetcode -342. 4的幂 -344.反转字符串 -345.反转字符串中的元音字母】
【Leetcode -342. 4的幂 -344.反转字符串 -345.反转字符串中的元音字母】
42 0
深入理解动态规划算法 | 最长公共子序列LCS
深入理解动态规划算法 | 最长公共子序列LCS
126 0
|
算法 C++
【动态规划篇】最少分割回文 && 编辑距离 && 不同的子序列
【动态规划篇】最少分割回文 && 编辑距离 && 不同的子序列
【动态规划篇】最少分割回文 && 编辑距离 && 不同的子序列
|
算法 Java 索引
最长回文子串
最长回文子串
120 0
最长回文子串
|
算法 PHP Python
最长公共子串- LCS 算法
最长公共子串- LCS 算法
97 0
|
算法
LeetCode算法:求出字符串的最大回文子串 及 长度【只利用字符串反转就可】
LeetCode算法:求出字符串的最大回文子串 及 长度【只利用字符串反转就可】
82 0
[解题报告](第24讲) 字符串算法(四) - 字符计数法(2)
[解题报告](第24讲) 字符串算法(四) - 字符计数法
[解题报告](第24讲) 字符串算法(四) - 字符计数法(2)
[解题报告](第24讲) 字符串算法(四) - 字符计数法(1)
[解题报告](第24讲) 字符串算法(四) - 字符计数法
[解题报告](第24讲) 字符串算法(四) - 字符计数法(1)