私はちょうど質問への答えを書きました:
この関数は、2 つの文字列の間で最も長い部分文字列を見つけることになっていますが、最悪の場合の実行時間とそれを引き起こす入力を突き止めようとすると、わからないことに気付きました。コードは C 疑似コードであると考えてください。
// assume the shorter string is passed in as A
int lcs(char * A, char * B)
{
int length_a = strlen(A);
int length_b = strlen(B);
// This holds the length of the longest common substring found so far
int longest_length_found = 0;
// for each character in one string (doesn't matter which), look for
// incrementally larger strings in the other
// once a longer substring can no longer be found, stop
for (int a_index = 0; a_index < length_a - longest_length_found; a_index++) {
for (int b_index = 0; b_index < length_b - longest_length_found; b_index++) {
// check the next letter until a mismatch is found or one of the strings ends.
for (int offset = 0;
A[a_index+offset] != '\0' &&
B[b_index+offset] != '\0' &&
A[a_index+offset] == B[b_index+offset];
offset++) {
longest_length_found = longest_length_found > offset ? longest_length_found : offset;
}
}
}
return longest_found_length;
}
これまでの私の考えは次のとおりです。
以下では、A B Aと言う必要がないように、A と B はほぼ同じサイズであると仮定します。単に n^3 とだけ言います。これがひどく悪い場合は、質問を更新できます。
コードにいくつかの最適化がなければ、ランタイムはN^3 ランタイムのA B A になると思います。
ただし、文字列が類似しておらず、長い部分文字列が見つからない場合、最も内側の for ループは定数にドロップアウトし、A*B が残りますよね?
文字列がまったく同じである場合、各文字列を同時に通過するパスは 1 つだけであるため、アルゴリズムは線形時間かかります。
文字列が類似しているが同一ではない場合、longest_length_found は A または B の小さい方のかなりの割合になり、N^3 の要因の 1 つを分割して N^2 になりますよね? 私は、それらが非常に似ているが同一ではない場合に何が起こるかを理解しようとしています.
声に出して考えてみると、最初の文字に、A の長さの約半分の長さの部分文字列が見つかったらどうなるでしょうか。これは、最初のループの A/2 反復、B-(A/2) 反復を実行することを意味します。 2 番目のループの、そして 3 番目のループで最大 A/2 反復 (文字列が非常に似ていると仮定) まで、より長い部分文字列を見つけることなく。文字列の長さがほぼ等しいと仮定すると、N/2 * N/2 * N/2 = O(N^3) になります。
この動作を示すサンプル文字列:
A A A B A A A B A A A B A A A B
A A A A B A A A A B A A A A B A
私は近くにいますか、それとも何かを見逃しているか、何かを誤って適用していますか?
トライ/プレフィックス ツリーを使用すればもっとうまくやれると確信していますが、繰り返しになりますが、この特定のコードの動作を理解することに本当に興味があります。