分割統治を利用する
分割: シーケンス n のサイズをサイズ n/2 の 2 つのリストにする 征服: 再帰的に数える 2 つのリストを結合する: これはトリックの部分です (線形時間で行うため)
組み合わせて、マージとカウントを使用します。2 つのリストが A、B であるとします。これらは既にソートされています。A、B から出力リスト L を生成し、反転の数 (a,b) もカウントします。ここで、a は A にあり、b は B にあり、a > b です。
アイデアは、マージソートの「マージ」に似ています。2 つのソートされたリストを 1 つの出力リストにマージしますが、反転もカウントします。
a_i が出力に追加されるたびに、a_i はリスト B に残っているすべてのものよりも小さいため、新しい反転は発生しません。b_j が出力に追加された場合、それは A の残りのすべての項目よりも小さいため、a_i の数を増やします。 A に残っている要素の数による反転の数。
マージアンドカウント(A,B) ; A,B 2 つの入力リスト (ソート済み) ; C 出力リスト ; i,j 各リストへの現在のポインタ、先頭から開始; i, j が指す a_i, b_j 要素。反転のカウント数、初期値は 0
while A,B != empty 追加 min(a_i,b_j) if b_j < a_i count += A に残っている要素の数 j++ else i++ ; 現在、1 つのリストは空です リストの残りを C に追加します return count, C
マージ アンド カウントを使用すると、カウント反転アルゴリズムを次のように設計できます。
sort-and-count(L) L の要素が 1 つの場合は 0 を返す そうでない場合は、L を A、B に分割します (rA, A) = sort-and-count(A) (rB, B) = sort-and-count(B) (r, L) = merge-and-count(A,B) return r = rA+rB+r, L
T(n) = O(n lg n)