基本的に次のように、任意の言語の O(n) でこれを行うことができます。
# Get min and max values O(n).
min = oldList[0]
max = oldList[0]
for i = 1 to oldList.size() - 1:
if oldList[i] < min:
min = oldList[i]
if oldList[i] > max:
max = oldList[i]
# Initialise boolean list O(n)
isInList = new boolean[max - min + 1]
for i = min to max:
isInList[i] = false
# Change booleans for values in old list O(n)
for i = 0 to oldList.size() - 1:
isInList[oldList[i] - min] = true
# Create new list from booleans O(n) (or O(1) based on integer range).
newList = []
for i = min to max:
if isInList[i - min]:
newList.append (i)
append
ここでは、実装者が脳死していない限り、O(1) 操作であると想定しています。したがって、各 O(n) ごとに k ステップを使用しても、O(n) 操作が必要です。
手順がコードで明示的に実行されるか、言語のカバーの下で実行されるかは関係ありません。それ以外の場合は、Cqsort
は 1 つの操作であり、O(1) ソート ルーチンの聖杯を手に入れたと主張できます :-)
多くの人が発見したように、多くの場合、空間の複雑さと時間の複雑さをトレードオフできます。たとえば、上記はisInList
andnewList
変数の導入が許可されているためにのみ機能します。これが許可されていない場合、次善の策は、リストをソートし(おそらくO(n log n)よりも優れていない)、その後にO(n)(私が思うに)操作を行って重複を削除することです。
極端な例として、約 40 億バイトを割り当てることができれば、同じ余分なスペースの方法を使用して、O(n) 時間で任意の数の 32 ビット整数 (それぞれが 255 個以下の重複しか持たないなど) をソートできます。カウントを保存します。
すべてのカウントをゼロに初期化し、リスト内の各位置を実行して、その位置の数に基づいてカウントをインクリメントするだけです。それが O(n) です。
次に、リストの先頭からカウント配列を実行し、その数の正しい値をリストに配置します。これは O(1) で、1 はもちろん約 40 億ですが、それでも時間は一定です :-)
これも O(1) 空間の複雑さですが、非常に大きな「1」です。通常、トレードオフはそれほど深刻ではありません。