我正在浏览一些关于geeksforgeeks的动态编程文章,并遇到了最长公共子序列问题。我没有想出自己的指数天真解决方案的实现,但是在解决了纸上问题的一些例子后,我提出了我认为成功实现O(n*m)
版本的内容。然而,OJ证明我错了。我的算法失败了输入字符串:
"LRBBMQBHCDARZOWKKYHIDDQSCDXRJMOWFRXSJYBLDBEFSARCBYNECDYGGXXPKLORELLNMPAPQFWKHOPKMCO"
"QHNWNKUEWHSQMGBBUQCLJJIVSWMDKQTBXIXMVTRRBLJPTNSNFWZQFJMAFADRRWSOFSBCNUVQHFFBSAQXWPQCAC"
我对算法的思考过程如下。我想维护一个DP数组,其长度是字符串a
的长度,其中a
是输入字符串中较小的一个。 dpA[i]
将是以a[i]
结尾的最长公共子序列。为此,我需要遍历索引a
中的字符串0 => length-1
并查看a[i]
中是否存在b
。如果a[i]
中存在b
,则它将位于pos
位置。
dp[i]
为1
dp[i]
标记为0
a[i]
是现有子序列的扩展,我们必须经过a
并找到i
后面的第一个与b
后面的值相匹配的字符{ {1}}。我们分别调用这些匹配值pos
和j
的索引。由于我们已涵盖所有k
且已填写a[0...i-1]
,因此我们保证此值已成为我们之前看到的值。当我们找到第一个匹配项dpA[0...i-1]
时,因为我们正在扩展以dpA[i] = dpA[j]+1
结尾的前一个子序列。冲洗重复。显然这种方法并不完美,或者我不会问这个问题,但我似乎无法看到算法的问题。我已经看了很长时间,我几乎不能再考虑它,但任何关于如何修复它的想法都将不胜感激!
a[j]
我认为复杂性实际上可能是int longestCommonSubsequenceString(const string& x, const string& y) {
string a = (x.length() < y.length()) ? x : y;
string b = (x.length() >= y.length()) ? x : y;
vector<int> dpA(a.length(), 0);
int pos;
bool breakFlag = false;
for (int i = 0; i < a.length(); ++i) {
pos = b.find_last_of(a[i]);
if (pos != string::npos) {
if (!dpA[i]) dpA[i] = 1;
for (int j = i-1; j >= 0; --j) {
for (int k = pos-1; k >= 0; --k) {
if (a[j] == b[k]) {
dpA[i] = dpA[j]+1;
breakFlag = true;
break;
}
if (breakFlag) break;
}
}
}
breakFlag = false;
}
return *max_element(dpA.begin(), dpA.end());
}