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
説明
考え方はシンプルです。文字列s1
and s2
については、次の方法で相殺しようとs2
しi
ます。
s1: abcabcabc
s2: bcabcab
オフセットが3の場合:
s1: abcabcabc
s2: bcabcab
次に、各offset i
に対して、s1[i:]
およびで動的プログラミングスキャンを実行しs2
ます。それぞれについてj
、聞かせてf[j, 0]
最大の長さでd
、その結果s1[j - d:j] == s2[j - i - d: j - i]
。同様に、文字列とがf[j, 1]
最大で1文字異なるd
ような最大長にしてください。s1[j - d:j]
s2[j - i - d:j - i]
以下のためだから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、:]の計算にはf [j-1、:]のみが必要なので、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;
}