-
-
Notifications
You must be signed in to change notification settings - Fork 46.6k
Added Median of Medians Algorithm #9864
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
82a8273
68a3fdb
c767c66
016dabb
328a2df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
""" | ||
A Python implementation of the Median of Medians algorithm | ||
to select pivots for quick_select, which is efficient for | ||
calculating the value that would appear in the index of a | ||
list if it would be sorted, even if it is not already | ||
sorted. Search in time complexity O(n) at any rank | ||
deterministically | ||
https://en.wikipedia.org/wiki/Median_of_medians | ||
""" | ||
|
||
""" | ||
>>> quick_select([2, 4, 5, 7, 899, 54, 32], 5) | ||
32 | ||
>>> quick_select([2, 4, 5, 7, 899, 54, 32], 1) | ||
2 | ||
>>> quick_select([5, 4, 3, 2], 2) | ||
3 | ||
>>> quick_select([3, 5, 7, 10, 2, 12], 3) | ||
5 | ||
""" | ||
|
||
|
||
def median_of_five(arr: list) -> int: | ||
""" | ||
>>> median_of_five([2, 4, 5, 7, 899]) | ||
5 | ||
>>> median_of_five([5, 7, 899, 54, 32]) | ||
32 | ||
>>> median_of_five([5, 4, 3, 2]) | ||
3 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test is failing:
|
||
>>> median_of_five([3, 5, 7, 10, 2]) | ||
5 | ||
""" | ||
""" | ||
Return the median of the input list | ||
:param arr: Array to find median of | ||
:return: median of arr | ||
""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you swap the order of the tests and explanation, and condense into a single docstring |
||
arr = sorted(arr) | ||
return arr[len(arr) // 2] | ||
|
||
|
||
def median_of_medians(arr: list) -> int: | ||
""" | ||
>>> median_of_medians([2, 4, 5, 7, 899, 54, 32]) | ||
54 | ||
>>> median_of_medians([5, 7, 899, 54, 32]) | ||
32 | ||
>>> median_of_medians([5, 4, 3, 2]) | ||
4 | ||
>>> median_of_medians([3, 5, 7, 10, 2, 12]) | ||
12 | ||
""" | ||
""" | ||
Return a pivot to partition data on by calculating | ||
Median of medians of input data | ||
:param arr: The data to be checked (a list) | ||
:return: median of medians of input array | ||
""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you swap the order of the tests and explanation, and condense into a single docstring |
||
if len(arr) <= 5: | ||
return median_of_five(arr) | ||
medians = [] | ||
i = 0 | ||
while i < len(arr): | ||
if (i + 4) <= len(arr): | ||
medians.append(median_of_five(arr[i:].copy())) | ||
else: | ||
medians.append(median_of_five(arr[i : i + 5].copy())) | ||
i += 5 | ||
return median_of_medians(medians) | ||
|
||
|
||
def quick_select(arr: list, target: int) -> int: | ||
""" | ||
>>> quick_select([2, 4, 5, 7, 899, 54, 32], 5) | ||
32 | ||
>>> quick_select([2, 4, 5, 7, 899, 54, 32], 1) | ||
2 | ||
>>> quick_select([5, 4, 3, 2], 2) | ||
3 | ||
>>> quick_select([3, 5, 7, 10, 2, 12], 3) | ||
5 | ||
""" | ||
|
||
""" | ||
Two way partition the data into smaller and greater lists, | ||
in relationship to the pivot | ||
:param arr: The data to be searched (a list) | ||
:param target: The rank to be searched | ||
:return: element at rank target | ||
""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you swap the order of the tests and explanation, and condense into a single docstring |
||
|
||
# Invalid Input | ||
if target > len(arr): | ||
return -1 | ||
|
||
# x is the estimated pivot by median of medians algorithm | ||
x = median_of_medians(arr) | ||
left = [] | ||
right = [] | ||
check = False | ||
for i in range(len(arr)): | ||
if arr[i] < x: | ||
left.append(arr[i]) | ||
elif arr[i] > x: | ||
right.append(arr[i]) | ||
elif arr[i] == x and not check: | ||
check = True | ||
else: | ||
right.append(arr[i]) | ||
rank_x = len(left) + 1 | ||
if rank_x == target: | ||
answer = x | ||
elif rank_x > target: | ||
answer = quick_select(left, target) | ||
elif rank_x < target: | ||
answer = quick_select(right, target - rank_x) | ||
return answer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no point in repeating the same tests here.