-
Notifications
You must be signed in to change notification settings - Fork 2
feat(algorithms, top k elements): smallest range covering elements from k lists #172
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
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
a18e3cb
feat(algorithms, top-k-elements): smallest range covering elements fr…
BrianLusina e5caaa0
feat(algorithms, top-k-elements): smallest range covering alements fr…
BrianLusina c8905e7
updating DIRECTORY.md
d8e1ec6
Update algorithms/top_k_elements/smallest_range_covering_k_lists/__in…
BrianLusina File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
295 changes: 295 additions & 0 deletions
295
algorithms/top_k_elements/smallest_range_covering_k_lists/README.md
Large diffs are not rendered by default.
Oops, something went wrong.
122 changes: 122 additions & 0 deletions
122
algorithms/top_k_elements/smallest_range_covering_k_lists/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| from collections import defaultdict | ||
| from typing import List, Tuple, DefaultDict | ||
| import heapq | ||
|
|
||
|
|
||
| def smallest_range(nums: List[List[int]]) -> List[int]: | ||
| # min heap that will store (value, list index, element index) for the smallest elements | ||
| min_heap: List[Tuple[int, int, int]] = [] | ||
| heapq.heapify(min_heap) | ||
| # Initialize the maximum value among the current elements in the heap | ||
| max_value = float("-inf") | ||
| # Initialize range boundaries with placeholders | ||
| range_start = 0 | ||
| range_end = float("inf") | ||
|
|
||
| number_of_lists = len(nums) | ||
|
|
||
| # insert the first elements from each list into the min-heap and update max_value to be the maximum value seen so far | ||
| for list_idx in range(number_of_lists): | ||
| # (value, list index, index within the list) | ||
| value = nums[list_idx][0] | ||
| heapq.heappush(min_heap, (value, list_idx, 0)) | ||
| # Track the max value among the current elements | ||
| max_value = max(max_value, value) | ||
|
|
||
| # Continue processing until we can't proceed further | ||
| while len(min_heap) == number_of_lists: | ||
| # Pop the smallest element from the heap (min_val from one of the lists) | ||
| min_value, row, col = heapq.heappop(min_heap) | ||
|
|
||
| # Update the smallest range if the current range is smaller | ||
| if max_value - min_value < range_end - range_start: | ||
| range_start = min_value | ||
| range_end = max_value | ||
|
|
||
| # If possible, add the next element from the same row to the heap | ||
| if col + 1 < len(nums[row]): | ||
| next_value = nums[row][col + 1] | ||
| # Push the next element from the same list | ||
| heapq.heappush(min_heap, (next_value, row, col + 1)) | ||
| # Update max_val if needed | ||
| max_value = max(max_value, next_value) | ||
|
|
||
| # If any list runs out of elements, we can't form a complete range anymore | ||
|
|
||
| # Return the smallest range found | ||
| return [range_start, range_end] | ||
|
|
||
|
|
||
| def smallest_range_two_pointer(nums: List[List[int]]) -> List[int]: | ||
| merged: List[Tuple[int, int]] = [] | ||
|
|
||
| # merge all lists with their list index | ||
| for list_idx, num_list in enumerate(nums): | ||
| for num in num_list: | ||
| merged.append((num, list_idx)) | ||
|
|
||
| # sort the merged list | ||
| merged.sort() | ||
|
|
||
| # Two pointers to track the smallest range | ||
| freq: DefaultDict[int, int] = defaultdict(int) | ||
| left, count = 0, 0 | ||
| range_start, range_end = 0, float("inf") | ||
|
|
||
| for right in range(len(merged)): | ||
| val = merged[right][1] | ||
| freq[val] += 1 | ||
| if freq[val] == 1: | ||
| count += 1 | ||
|
|
||
| # when all lists are represented, try to shrink the window | ||
| while count == len(nums): | ||
| current_range = merged[right][0] - merged[left][0] | ||
| if current_range < range_end - range_start: | ||
| range_start = merged[left][0] | ||
| range_end = merged[right][0] | ||
|
|
||
| freq[merged[left][1]] -= 1 | ||
| if freq[merged[left][1]] == 0: | ||
| count -= 1 | ||
|
|
||
| left += 1 | ||
|
|
||
| return [range_start, range_end] | ||
|
|
||
|
|
||
| def smallest_range_brute_force(nums: List[List[int]]) -> List[int]: | ||
| k = len(nums) | ||
| # Stores the current index of each list | ||
| indices = [0] * k | ||
| # To track the smallest range | ||
| range_list = [0, float("inf")] | ||
|
|
||
| while True: | ||
| cur_min, cur_max = float("inf"), float("-inf") | ||
| min_list_index = 0 | ||
|
|
||
| # Find the current minimum and maximum values across the lists | ||
| for i in range(k): | ||
| current_element = nums[i][indices[i]] | ||
|
|
||
| # Update the current minimum | ||
| if current_element < cur_min: | ||
| cur_min = current_element | ||
| min_list_index = i | ||
|
|
||
| # Update the current maximum | ||
| if current_element > cur_max: | ||
| cur_max = current_element | ||
|
|
||
| # Update the range if a smaller one is found | ||
| if cur_max - cur_min < range_list[1] - range_list[0]: | ||
| range_list[0] = cur_min | ||
| range_list[1] = cur_max | ||
|
|
||
| # Move to the next element in the list that had the minimum value | ||
| indices[min_list_index] += 1 | ||
| if indices[min_list_index] == len(nums[min_list_index]): | ||
| break | ||
|
|
||
| return range_list | ||
Binary file added
BIN
+30.9 KB
...sts/images/examples/smallest_range_covering_elements_from_k_lists_example_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+32.6 KB
...sts/images/examples/smallest_range_covering_elements_from_k_lists_example_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+31.6 KB
...sts/images/examples/smallest_range_covering_elements_from_k_lists_example_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+16.7 KB
...ges/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+39.6 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+28.5 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+28.1 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_12.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+39.9 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_13.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+28.4 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_14.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+30.7 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_15.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+39.4 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+28.5 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_17.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+28.3 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_18.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+40.9 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_19.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+30 KB
...ges/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+28.4 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_20.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+28.2 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_21.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+30.2 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_22.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+26.7 KB
...es/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_23.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+33.3 KB
...ges/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+27.3 KB
...ges/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+28.8 KB
...ges/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+29.5 KB
...ges/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+39.8 KB
...ges/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+27.8 KB
...ges/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+30.2 KB
...ges/solutions/smallest_range_covering_elements_from_k_lists_heap_solution_9.png
Oops, something went wrong.
Binary file added
BIN
+55.7 KB
...utions/smallest_range_covering_elements_from_k_lists_two_pointer_solution_1.png
Oops, something went wrong.
Binary file added
BIN
+60.8 KB
...utions/smallest_range_covering_elements_from_k_lists_two_pointer_solution_2.png
Oops, something went wrong.
Binary file added
BIN
+34.8 KB
...utions/smallest_range_covering_elements_from_k_lists_two_pointer_solution_3.png
Oops, something went wrong.
Binary file added
BIN
+32.5 KB
...utions/smallest_range_covering_elements_from_k_lists_two_pointer_solution_4.png
Oops, something went wrong.
Binary file added
BIN
+51.9 KB
...utions/smallest_range_covering_elements_from_k_lists_two_pointer_solution_5.png
Oops, something went wrong.
Binary file added
BIN
+42.8 KB
...utions/smallest_range_covering_elements_from_k_lists_two_pointer_solution_6.png
Oops, something went wrong.
Binary file added
BIN
+37.9 KB
...utions/smallest_range_covering_elements_from_k_lists_two_pointer_solution_7.png
Oops, something went wrong.
Binary file added
BIN
+31.9 KB
...utions/smallest_range_covering_elements_from_k_lists_two_pointer_solution_8.png
Oops, something went wrong.
Binary file added
BIN
+50.9 KB
...utions/smallest_range_covering_elements_from_k_lists_two_pointer_solution_9.png
Oops, something went wrong.
46 changes: 46 additions & 0 deletions
46
...nts/smallest_range_covering_k_lists/test_smallest_range_covering_elements_from_k_lists.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| import unittest | ||
| from typing import List | ||
| from parameterized import parameterized | ||
| from algorithms.top_k_elements.smallest_range_covering_k_lists import ( | ||
| smallest_range, | ||
| smallest_range_two_pointer, | ||
| smallest_range_brute_force, | ||
| ) | ||
|
|
||
| SMALLEST_RANGE_COVERING_ELEMENTS_FROM_K_LISTS_TESTS = [ | ||
| ([[4, 10, 15, 24, 26], [0, 9, 12, 20], [5, 18, 22, 30]], [20, 24]), | ||
| ([[1, 2, 3], [1, 2, 3], [1, 2, 3]], [1, 1]), | ||
| ([[1, 5, 8], [4, 12], [7, 8, 10]], [4, 7]), | ||
| ([[2, 6, 10], [1, 5, 9], [4, 8, 12]], [4, 6]), | ||
| ([[1, 3, 7], [2, 4, 8], [5, 6, 9]], [3, 5]), | ||
| ([[1, 5], [3, 7], [4, 6]], [3, 5]), | ||
| ([[1, 5], [4, 6], [6, 8], [11, 15]], [5, 11]), | ||
| ([[1, 5]], [1, 1]), | ||
| ([[1, 9], [3, 8], [4, 4]], [1, 4]), | ||
| ([[1, 2], [3, 4], [8, 8]], [2, 8]), | ||
| ] | ||
|
|
||
|
|
||
| class SmallestRangeCoveringElementsFromKListsTestCase(unittest.TestCase): | ||
| @parameterized.expand(SMALLEST_RANGE_COVERING_ELEMENTS_FROM_K_LISTS_TESTS) | ||
| def test_smallest_range(self, nums: List[List[int]], expected: List[int]): | ||
| actual = smallest_range(nums) | ||
| self.assertEqual(expected, actual) | ||
|
|
||
| @parameterized.expand(SMALLEST_RANGE_COVERING_ELEMENTS_FROM_K_LISTS_TESTS) | ||
| def test_smallest_range_two_pointers( | ||
| self, nums: List[List[int]], expected: List[int] | ||
| ): | ||
| actual = smallest_range_two_pointer(nums) | ||
| self.assertEqual(expected, actual) | ||
|
|
||
| @parameterized.expand(SMALLEST_RANGE_COVERING_ELEMENTS_FROM_K_LISTS_TESTS) | ||
| def test_smallest_range_brute_force( | ||
| self, nums: List[List[int]], expected: List[int] | ||
| ): | ||
| actual = smallest_range_brute_force(nums) | ||
| self.assertEqual(expected, actual) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| unittest.main() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.