O(n ^ 2 log n + k)よりも少し良いことができると思います。
あなたが i の位置にいるとします。i (1...i) までのすべての要素は 1 つの BST に格納され、i (1+1...n) 以降のすべての要素は 2 番目の BST に格納されます。
最初のツリーで、A[j] となるような最小の要素 A[j] を見つけます。
次に、2 番目のツリーで、A[k] < kA[i]-A[j] となる最大の要素 A[k] を見つけます。A[k]<=A[i] の場合は停止します。それ以外の場合は、A[j]、A[i]、A[k] を出力し、2 番目のツリーで k = prev(A[k]) を設定します。A[k]<=A[i] になるまでループします。
このすべての途中で、追加の比較を行います。A[j1] = next(A[j]) とします (つまり、A[j1] はソートされたシーケンスの次の要素です)。ak が条件 A[j1]+A[i]+A[k] <=t にも従う場合、そのような最大の k を書き留めます。次の反復では、二分探索の代わりにこの k を直接使用します。
最初に i=2、firstTree={A[1]}、secondTree = {A[3]..A[n]} から開始します。A[i] を増やすときはいつでも、A[i] を最初のツリーに追加し、2 番目のツリーから A[i+1] を削除します。
全体的な時間の複雑さ: O(n^2+n*log(n)) + O(p) = O(n^2+p) ここで、p は合計結果の数です。
アルゴリズム:
Initialization: firstTree={A[1]}, secondTree = {A[3]..A[n]}
For i = 2:(n-1) do:
j = getFirst(firstTree)
firstIter = true;
while(true)
if A[j]>=A[i] or A[j]+A[i]>t break
if firstIter:
k = binSearch(secondTree, t - A[i] -A[j])
firstIter=false
else
if bestk<0:
break;
k = bestk
bestk = -1
jnext = nextElement(firstTree, A[j]);
while (A[k]>A[i]):
print (A[j], A[i], A[k])
if bestk<0 and A[i]+A[jnext]+A[k] < t:
bestk = k;
k = prevElement(secondTree, A[k])
Add(firstTree, A[i])
Remove(secondTree, A[i+1])
binSearch は i ごとに 1 回だけ呼び出され、1 つの i に対して nextElement はツリーを 1 回だけ通過することに注意してください (複雑さ O(n))。内側の while ループは 1 回だけ呼び出されます。したがって、全体的な複雑さは O(n^2 + nlogn + p) で、p は出力の数です。
編集: 成果のない j (つまり、j の解がない) が見つかった場合は停止します。このコストは O(p) 自体に組み込まれていると思います。したがって、最終的な複雑さは O(nlogn + p) です。申し訳ありませんが、詳細な証明を提供する時間がありません。