使用递归的最长公共子序列
Longest common subsequence using recursion
基本上,我试图使用递归来解决最长的公共子序列问题。在其中一个网站上,我应该写下以下形式的函数;
int longestCommonSubstr (string S1, string S2, int n, int m)
{
// your code here
}
当给出附加参数n
和m
时,我可以编写它的递归代码。其中n and m
分别是串S1、S2的长度。另一个网站要求我解决同样的问题,但没有提供n
和m
,如下所示;
int longestCommonSubstr (string S1, string S2)
{
// your code here
}
对于第一个站点,我的完整递归函数如下所示;
int longestCommonSubstr (string S1, string S2, int n, int m)
{
// your code here
if(n==0 || m==0){
return 0;
}
if(S1[n-1]==S2[m-1]){
return 1+longestCommonSubstr(S1,S2,n-1,m-1);
}
else{
return max(longestCommonSubstr(S1,S2,n-1,m),longestCommonSubstr(S1,S2,n,m-1));
}
}
但当我们不允许使用参数n
和m
作为第二种情况时,我无法编写递归代码很乐意寻求帮助来处理第二种情况的递归代码。
如果需要,您完全可以使用递归解决方案。毕竟,函数可以调用其他函数。只需计算它们并将它们传递给递归函数即可。
但这只是部分帮助。即使是极客对极客(顺便说一句,这是一个糟糕的网站(,时间复杂性要求也是O(n*m(,递归无法满足这一要求。
这不仅仅是一个递归练习,也是一个动态编程练习。递归解决方案通常被认为是";暴力";解决方案,因为它通常必须重复解决相同的子问题。
您可以通过记忆已经遇到的子解决方案(也称为自上而下的方法(来帮助自己,但每次迭代仍要进行大约三次递归调用。
您需要更进一步,并派生出一个自下而上的解决方案。
我们将创建一个2D阵列。行是S1
的字符,列是S2
的行。我们将在开头添加一行和一列,以表示其他字符串为空。
因此,给定:S1 = "ABCDGH";
和S2 = "ACDGHR;"
,我们从一个数组开始,我将称之为counts
:
0 A C D G H R
0 0 0 0 0 0 0 0
A 0
B 0
C 0
D 0
G 0
H 0
然后我们可以进行直接的人物间比较。如果是S1[i] == S2[j]
,我们将1
添加到counts[i - 1][j - 1]
的值中。这就是我们跟踪子字符串长度的方式。我们将保留最大长度的值,只要找到两个匹配的字符,我们就会根据需要更新最大长度。
如果是S1[i] != S2[j]
,我们只需将0
存储在counts[i][j]
中。当我们填满整个2D阵列时,我们知道了最大值。不需要递归。
以下是填充数组的样子:
0 A C D G H R
0 0 0 0 0 0 0 0
A 0 1 0 0 0 0 0
B 0 0 0 0 0 0 0
C 0 0 1 0 0 0 0
D 0 0 0 2 0 0 0
G 0 0 0 0 3 0 0
H 0 0 0 0 0 4 0
这是代码:
class Solution {
public:
std::vector<std::vector<int>> substrCounts(S1.length() + 1,
std::vector<int>(S2.length() + 1));
int maxCount = 0;
for (std::size_t rowIdx = 1; rowIdx < substrCounts.size(); ++rowIdx) {
for (std::size_t columnIdx = 1; columnIdx < substrCounts[0].size();
++columnIdx) {
if (S1[rowIdx - 1] == S2[columnIdx - 1]) {
substrCounts[rowIdx][columnIdx] =
substrCounts[rowIdx - 1][columnIdx - 1] + 1;
maxCount = std::max(maxCount, substrCounts[rowIdx][columnIdx]);
} else {
substrCounts[rowIdx][columnIdx] = 0;
}
}
}
return maxCount;
}
};
它通过了所有119个关于极客的极客测试用例,他们以0.05秒计算运行时间。您还会注意到,我根本不关心n
或m
;它们是不需要的。
我通常只会更改签名,但网站不允许。然后我应该将未使用的参数强制转换为void
,但网站运行时根本没有任何警告,这让你可以编写你能想象到的最糟糕的代码。我没有为演员阵容而烦恼,只是因为我觉得自己很懒,当你被迫使用#include <bits/stdc++.h>
和using namespace std;
时,喋喋不休地谈论最佳实践是毫无意义的。
- 通过递归进行因子分解
- 递归函数计算序列中的平方和(并输出过程)
- 使用递归的数组的最小值.这是怎么回事
- 递归列出所有目录中的C++与Python与Ruby的性能
- 递归计数给定目录的文件和所有目录
- 如何在BST的这个简单递归实现中消除警告
- C++:正在检查LinkedList中的回文-递归方法-错误
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 递归无序映射
- TSP递归解的迭代形式
- 如何在Elixir中调用递归函数并行
- 返回递归调用和仅递归调用的区别
- 数组元素打印的递归方法
- 使用递归时获取变量的奇怪值
- 如何在C++中递归地按相反顺序打印集合
- 到连接组件算法的问题(递归)
- 如何使用递归打印修改后的星号三角形图案
- 使用递归模板动态分配的多维数组
- 递归函数有效,但无法记忆
- 包含模板文件的递归会导致编译失败