Sort a Nearly Sorted List
Problem
A sensor log arrives almost in order: every reading is at most k positions away from the place it would occupy in the fully sorted log. Given the list and k, return the readings in ascending order. The answer should take O(n log k) time, which beats a general sort when k is much smaller than n.
Examples
Input: nums = [3, 1, 2, 6, 4, 5], k = 2
Output: [1, 2, 3, 4, 5, 6]
Why: 3 sits two places early, 1 and 2 one place late
Input: nums = [10, 9, 8, 7], k = 3
Output: [7, 8, 9, 10]
Why: a reversed list of four values is still within 3 places
Input: nums = [1, 2, 3], k = 0
Output: [1, 2, 3]
Why: edge case, k = 0 means everything is already in place
Hints
0 / 3
Think about the very first slot of the answer. Which positions of the input can the smallest value possibly come from?
It must come from the first k + 1 positions. The same is true for every later slot, so only a small moving group of candidates matters at any moment, and a min-heap keeps such a group ordered.
Push values into a min-heap one at a time. Whenever the heap holds more than k values, pop its smallest into the output, because nothing still unread can be smaller. When the input runs out, pop the rest in order.
Solution
The value that belongs in output slot i starts at most k positions away, so it is already among the values read once k + 1 of them are waiting. Keeping those candidates in a min-heap of size k + 1 means the heap's smallest value is always safe to emit, since every unread value belongs further right. Heap sort pops a heap holding everything, while this heap never holds more than k + 1 values, and that is where the log k comes from. Time is O(n log k), and space is O(k) for the heap plus the output.
import heapq
def sort_nearly(nums, k):
heap, out = [], []
for x in nums:
heapq.heappush(heap, x)
if len(heap) > k: # k + 1 candidates: the smallest is final
out.append(heapq.heappop(heap))
while heap: # input exhausted, drain in order
out.append(heapq.heappop(heap))
return out
print(sort_nearly([3, 1, 2, 6, 4, 5], 2)) # -> [1, 2, 3, 4, 5, 6]
print(sort_nearly([10, 9, 8, 7], 3)) # -> [7, 8, 9, 10]
print(sort_nearly([1, 2, 3], 0)) # -> [1, 2, 3]Stuck on the idea rather than the code? Heap Sort covers it.