您可以使用任何语言在 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) 操作,除非实施者脑残,否则它应该是。所以每k步O(n),你仍然有一个O(n)操作。
这些步骤是在您的代码中明确完成还是在语言的掩护下完成是无关紧要的。否则,您可以声称 Cqsort
是一个操作,并且您现在拥有 O(1) 排序例程的圣杯 :-)
正如许多人所发现的那样,您通常可以用空间复杂度来换取时间复杂度。例如,上面的方法之所以有效,是因为我们可以引入isInList
andnewList
变量。如果不允许这样做,下一个最佳解决方案可能是对列表进行排序(可能没有更好的 O(n log n)),然后是 O(n)(我认为)操作以删除重复项。
一个极端的例子,你可以使用相同的额外空间方法在 O(n) 时间内对任意数量的 32 位整数(比如每个只有 255 个或更少的重复项)进行排序,前提是你可以为大约 40 亿字节分配存储计数。
只需将所有计数初始化为零并遍历列表中的每个位置,根据该位置的数字递增计数。那是 O(n)。
然后从列表的开头开始遍历 count 数组,将许多正确的值放入列表中。那是 O(1),当然 1 大约是 40 亿,但仍然是恒定的时间:-)
这也是 O(1) 空间复杂度,但是一个非常大的“1”。通常,权衡并不那么严重。