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
6465if __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