-
-
Notifications
You must be signed in to change notification settings - Fork 50.4k
Expand file tree
/
Copy pathmedian_of_medians.py
More file actions
69 lines (52 loc) · 1.82 KB
/
median_of_medians.py
File metadata and controls
69 lines (52 loc) · 1.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
"""
Median of Medians Algorithm
Guarantees O(n) worst-case time complexity for finding the k-th smallest element.
Reference: https://en.wikipedia.org/wiki/Median_of_medians
"""
def partition(arr: list, pivot: int) -> tuple[list, list, list]:
"""
Partition array into elements less than, equal to, and greater than pivot.
>>> partition([3, 1, 4, 1, 5], 3)
([1, 1], [3], [4, 5])
>>> partition([7, 7, 7], 7)
([], [7, 7, 7], [])
"""
low = [x for x in arr if x < pivot]
equal = [x for x in arr if x == pivot]
high = [x for x in arr if x > pivot]
return low, equal, high
def median_of_medians(arr: list, rank: int) -> int:
"""
Find the k-th smallest element in an unsorted list using Median of Medians.
Args:
arr: List of comparable elements
rank: 1-based index of the desired smallest element
Returns:
The k-th smallest element in arr
Raises:
ValueError: If rank is out of range
>>> median_of_medians([3, 1, 4, 1, 5, 9, 2, 6], 3)
2
>>> median_of_medians([7, 2, 10, 5], 1)
2
>>> median_of_medians([1, 2, 3, 4, 5], 5)
5
"""
if not 1 <= rank <= len(arr):
msg = f"rank={rank} is out of range for array of length {len(arr)}"
raise ValueError(msg)
if len(arr) <= 5:
return sorted(arr)[rank - 1]
chunks = [arr[i : i + 5] for i in range(0, len(arr), 5)]
medians = [sorted(chunk)[len(chunk) // 2] for chunk in chunks]
pivot = median_of_medians(medians, len(medians) // 2 + 1)
low, equal, high = partition(arr, pivot)
if rank <= len(low):
return median_of_medians(low, rank)
elif rank <= len(low) + len(equal):
return pivot
else:
return median_of_medians(high, rank - len(low) - len(equal))
if __name__ == "__main__":
import doctest
doctest.testmod()