A catalog of data structures and problems with approaches to solve them
You are given a list of N numbers, in which each number is located at most k places away from its sorted position. For example, if k = 1, a given element at index 4 might end up at indices 3, 4, or 5.
Come up with an algorithm that sorts this list in O(N log k) time.
A good place to start would be to use the sliding window technique. At each position, we find the minimum of the next k elements. If this element is less than the left of the window, we swap them.
def sort(array:list, k:int) -> list:
for i in range(len(array)):
low = i
window = array[i + 1: i + k + 1]
for j, item in enumerate(window, i + 1):
if item < array[i]:
low = j
if array[low] < array[i]:
array[i], array[low] = array[low], array[i]
return array
array = [2, 1, 3, 4, 1]
k = 3
sort(array, k)
[1, 1, 2, 3, 4]
Since we are iterating over N windows of size k, the time complexity is O(N * k). We also need O(k) space to store the window at any given time.
But the problem requires that we solve it in O(N log k) time. We can improve on our solution by using a heap.
import heapq
def sort_k(array:list, k:int) -> list:
res = []
heap = []
for i in range(k):
heapq.heappush(heap, array[i])
for i in range(k, len(array)):
heapq.heappush(heap, array[i])
smallest = heapq.heappop(heap)
res.append(smallest)
while heap:
res.append(heapq.heappop(heap))
return res
array = [2, 1, 3, 4, 1]
sort_k(array, k=3)
[1, 1, 2, 3, 4]
Since each push and pop overation in a heap takes O(log K) time, and since we are performing each of these operations N times, this algorithm will satisfy our requirement of O(N log K).
The space complexity will be O(N) because of storing the elements in an auxiliary results array.