C ++时间:O(n ^ 2),额外空间:O(1)
完成我的计算机上的15K数据需要0.2秒。
要编译它,请使用:
g++ -std=c++11 -O3 code.cpp -o code
要运行它,请使用:
./code < INPUT_FILE_THAT_CONTAINS_TWO_LINES_SPERATED_BY_A_LINE_BREAK
讲解
这个想法很简单,对于string s1
和s2
,我们尝试s2
通过i
以下方式抵消:
s1: abcabcabc
s2: bcabcab
当offset为3时:
s1: abcabcabc
s2: bcabcab
然后,对于每个偏移量i
,我们在s1[i:]
和上执行动态编程扫描s2
。对于每一个j
,令f[j, 0]
最大长度d
为s1[j - d:j] == s2[j - i - d: j - i]
。同样,设f[j, 1]
最大长度d
,以使字符串s1[j - d:j]
和之间s2[j - i - d:j - i]
相差最多1个字符。
因此s1[j] == s2[j - i]
,我们有:
f[j, 0] = f[j - 1, 0] + 1 // concat solution in f[j - 1, 0] and s1[j]
f[j, 1] = f[j - 1, 1] + 1 // concat solution in f[j - 1, 1] and s1[j]
除此以外:
f[j, 0] = 0 // the only choice is empty string
f[j, 1] = f[j - 1, 0] + 1 // concat solution in f[j - 1, 0] and s1[j] (or s2[j - i])
和:
f[-1, 0] = f[-1, 1] = 0
由于我们只需要f [j-1,:]来计算f [j,:],因此仅使用O(1)多余的空间。
最后,最大长度为:
max(f[j, 1] for all valid j and all i)
码
#include <string>
#include <cassert>
#include <iostream>
using namespace std;
int main() {
string s1, s2;
getline(cin, s1);
getline(cin, s2);
int n1, n2;
n1 = s1.size();
n2 = s2.size();
int max_len = 0;
int max_end = -1;
for(int i = 1 - n2; i < n1; i++) {
int f0, f1;
int max_len2 = 0;
int max_end2 = -1;
f0 = f1 = 0;
for(int j = max(i, 0), j_end = min(n1, i + n2); j < j_end; j++) {
if(s1[j] == s2[j - i]) {
f0 += 1;
f1 += 1;
} else {
f1 = f0 + 1;
f0 = 0;
}
if(f1 > max_len2) {
max_len2 = f1;
max_end2 = j + 1;
}
}
if(max_len2 > max_len) {
max_len = max_len2;
max_end = max_end2;
}
}
assert(max_end != -1);
// cout << max_len << endl;
cout << max_end - max_len + 1 << " " << max_end << endl;
}