Skip to content

Commit 8f54ac1

Browse files
fix: add doctest to partition and rename k to rank
1 parent b6f8f16 commit 8f54ac1

File tree

1 file changed

+29
-34
lines changed

1 file changed

+29
-34
lines changed

maths/median_of_medians.py

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,68 +5,63 @@
55
"""
66

77

8-
def partition(arr: list, pivot: int) -> tuple:
9-
"""Partition array into elements less than, equal to, and greater than pivot."""
8+
def partition(arr: list, pivot: int) -> tuple[list, list, list]:
9+
"""
10+
Partition array into elements less than, equal to, and greater than pivot.
11+
12+
>>> partition([3, 1, 4, 1, 5], 3)
13+
([1, 1], [3], [4, 5])
14+
>>> partition([7, 7, 7], 7)
15+
([], [7, 7, 7], [])
16+
"""
1017
low = [x for x in arr if x < pivot]
11-
high = [x for x in arr if x > pivot]
1218
equal = [x for x in arr if x == pivot]
19+
high = [x for x in arr if x > pivot]
1320
return low, equal, high
1421

1522

16-
def median_of_medians(arr: list, k: int) -> int:
23+
def median_of_medians(arr: list, rank: int) -> int:
1724
"""
1825
Find the k-th smallest element in an unsorted list using Median of Medians.
1926
2027
Args:
2128
arr: List of comparable elements
22-
k: 1-based index of the desired smallest element
29+
rank: 1-based index of the desired smallest element
2330
2431
Returns:
2532
The k-th smallest element in arr
2633
2734
Raises:
28-
ValueError: If k is out of range
29-
30-
Examples:
31-
>>> median_of_medians([3, 1, 4, 1, 5, 9, 2, 6], 3)
32-
2
33-
>>> median_of_medians([7, 2, 10, 5], 1)
34-
2
35-
>>> median_of_medians([1, 2, 3, 4, 5], 5)
36-
5
35+
ValueError: If rank is out of range
36+
37+
>>> median_of_medians([3, 1, 4, 1, 5, 9, 2, 6], 3)
38+
2
39+
>>> median_of_medians([7, 2, 10, 5], 1)
40+
2
41+
>>> median_of_medians([1, 2, 3, 4, 5], 5)
42+
5
3743
"""
38-
if not 1 <= k <= len(arr):
39-
raise ValueError(f"k={k} is out of range for array of length {len(arr)}")
44+
if not 1 <= rank <= len(arr):
45+
raise ValueError(f"rank={rank} is out of range for array of length {len(arr)}")
4046

41-
# Base case
4247
if len(arr) <= 5:
43-
return sorted(arr)[k - 1]
48+
return sorted(arr)[rank - 1]
4449

45-
# Step 1: Divide into chunks of 5 and find median of each chunk
46-
chunks = [arr[i : i + 5] for i in range(0, len(arr), 5)]
50+
chunks = [arr[i: i + 5] for i in range(0, len(arr), 5)]
4751
medians = [sorted(chunk)[len(chunk) // 2] for chunk in chunks]
4852

49-
# Step 2: Recursively find median of medians
5053
pivot = median_of_medians(medians, len(medians) // 2 + 1)
5154

52-
# Step 3: Partition around pivot
5355
low, equal, high = partition(arr, pivot)
5456

55-
# Step 4: Recurse into the correct partition
56-
if k <= len(low):
57-
return median_of_medians(low, k)
58-
elif k <= len(low) + len(equal):
57+
if rank <= len(low):
58+
return median_of_medians(low, rank)
59+
elif rank <= len(low) + len(equal):
5960
return pivot
6061
else:
61-
return median_of_medians(high, k - len(low) - len(equal))
62+
return median_of_medians(high, rank - len(low) - len(equal))
6263

6364

6465
if __name__ == "__main__":
6566
import doctest
66-
67-
doctest.testmod()
68-
69-
sample = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
70-
print(f"Array: {sample}")
71-
for i in range(1, len(sample) + 1):
72-
print(f" {i}-th smallest: {median_of_medians(sample, i)}")
67+
doctest.testmod()

0 commit comments

Comments
 (0)