編集:以下の答えは、そのように合計される1つのトリプレットのみが必要なこの問題のバージョンに適用されます。それらすべてが必要な場合、少なくとも O(n^2) の可能な出力 (ex0du5 で指摘されているように) が存在する可能性があり、繰り返される要素の病理学的なケースでは O(n^3) でさえあるため、ハッシュ (値からその値を持つインデックスのリストへのマッピング) に基づく単純な O(n^2) アルゴリズムよりも優れています。
これは基本的に 3SUM 問題です。潜在的に無限に大きな要素がない場合、最もよく知られているアルゴリズムは約 ですが、ほとんどの計算モデルO(n^2)
よりも高速にならないことを証明しただけです。O(n lg n)
整数要素が範囲内にある場合は、FFT[u, v]
を使用して、これのわずかに異なるバージョンを実行できます。この問題をあの問題に変換し、そこで解決し、この変換に基づいて問題の答えを導き出すプロセスについて説明します。O(n + (v-u) lg (v-u))
私が FFT で解決する方法を知っている問題は、配列内で長さ 3 の算術シーケンスa
をb
見つけるc
ことc - b = b - a
ですa + c = 2b
。
残念ながら、元の変換の最後のステップは、私が望むほど速くはありませんが、そこに到達したときにそれについて話します.
X
整数を含む元の配列を呼び出しましょうx_1, ..., x_n
。のようなインデックスi
、を見つけたいと思います。j
k
x_i + x_j = x_k
時間内の最小値u
と最大値v
を見つけます。ありのままに。_ _X
O(n)
u'
min(u, u*2)
v'
max(v, v*2)
Z
長さのバイナリ配列 (ビット文字列) を構築しv' - u' + 1
ます。またはその doubleに が含まれてZ[i]
いる場合は true になります。これは初期化です。の各要素を調べて、 の 2 つの対応する要素を設定するだけです。X
[x_1*2, ..., x_n*2]
u' + i
O(n)
X
Z
この配列を構築しているとき、見つかった重複のインデックスを補助リストに保存できますY
。が完了したら、 for eachをZ
チェックします。存在する場合は、完了です。それ以外の場合、重複は無関係であり、忘れることができます。(わずかに複雑な唯一の状況は、が繰り返される場合です。その場合、解決策を得るには、その 3 つの異なるコピーが必要です。)2 * x_i
x_i
Y
Y
0
ここで、問題の解、つまりは、 3 つの等間隔の解としてx_i + x_j = x_k
表示されます。これは、いくつかの単純な代数操作によって が得られるためです。両端の要素は特別な二重エントリ ( から) であり、中央の要素は通常のエントリ ( から) であることに注意してください。Z
2*x_j - x_k = x_k - 2*x_i
2X
X
次数の項の係数が であるZ
多項式 の表現と考えてください。がの場合、は(1、2、3、4、5、6、および 10 があるため) です。は1 + x + x 2 + x 3 + x 4 + x 5 + x 9です。p
i
Z[i]
X
[1, 2, 3, 5]
Z
1111110001
p
ここで、高校の代数から、2 つの多項式の積におけるx cの係数は、 x aに対する最初の多項式の係数の a + b = c にx bに対する2番目の係数を掛けた、すべての a、bの合計であることを思い出してください。したがって、q = p 2を考慮すると、 x 2j ( の a jの場合)の係数は、 のすべてのiの合計になります。しかし、は 2 進数であるため、これは で等間隔に配置されたトリプレットi、j、kの数とまったく同じです。(j、j、j)に注意してくださいZ[j] = 1
Z[i] * Z[2*j - i]
Z
Z
は常にそのようなトリプレットであるため、値が 1 より大きいもののみを考慮します。
次に、高速フーリエ変換を使用して、時間内にp 2を見つけることができます。ここで、は です。係数の別の配列を取得します。それを呼び出します。O(|Z| log |Z|)
|Z|
v' - u' + 1
W
x_k
のそれぞれをループしますX
。(必要な等間隔のものはすべて、X
ではなくの要素を中心にしていることを思い出してください2*X
。) この要素の 2 倍に対応するW
、つまりW[2*(x_k - u')]
が 1 である場合、それが自明でないプログレッションの中心ではないことがわかり、それをスキップできます。(前に議論したように、それは正の整数のみであるべきです。)
それ以外の場合は、必要な進行の中心になる可能性があります (したがって、 と を見つける必要がありますi
) j
。しかし、残念なことに、それは私たちの望む形を持たない進行の中心である可能性もあります. したがって、確認する必要があります。の他の要素x_i
をループし、,X
を含むトリプルがあるかどうかを確認します( を確認して)。もしそうなら、答えがあります。ヒットせずにすべて通過した場合、FFT は偽の答えしか見つけられず、 の別の要素をチェックする必要があります。2*x_i
x_k
2*x_j
j
Z[2*(x_k - x_j) - u']
X
W
したがって、この最後のステップは O(n * 1 + (実際には解ではない W[2*(x_k - u')] > 1 の x_k の数))O(n^2)
です。出力でこれらの誤った回答が生成されるのを回避する方法が必要W
です。適切なW
係数が確実に答えを持っていることがわかっていれば、この最後のステップO(n)
ですべてがうまくいくでしょう。
これを行うために多少異なる多項式を使用することは可能だと思いますが、実際には機能していません。もう少し考えてみます……。
この回答に部分的に基づいています。