-
Notifications
You must be signed in to change notification settings - Fork 2
feat(algorithms, dynamic-programming): counting bits #153
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 5 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
51b6979
feat(algorithms, dynamic-programming): counting bits
BrianLusina 8722c3a
updating DIRECTORY.md
91aef34
Update algorithms/heap/mergeksortedlists/test_merge_k_sorted_lists.py
BrianLusina 2fa26f6
Update algorithms/heap/mergeksortedlists/__init__.py
BrianLusina dce0b1c
Update algorithms/heap/kclosestelements/README.md
BrianLusina 434692c
Update algorithms/heap/kclosestelements/README.md
BrianLusina 9fa0e94
feat(algorithms, dynamic-programming): min cost to paint houses
BrianLusina 28a2794
updating DIRECTORY.md
26343df
docs(algorithms, dynamic-programming): update readme
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
Some comments aren't visible on the classic Files Changed page.
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
File renamed without changes.
File renamed without changes.
File renamed without changes.
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,78 @@ | ||
| # Counting Bits | ||
|
|
||
| Given an integer n, return an array ans of length n + 1 such that for each i (0 <= i <= n), ans[i] is the number of 1's | ||
| in the binary representation of i. | ||
|
|
||
| ## Examples | ||
|
|
||
| ```text | ||
| Example 1: | ||
| Input: n = 2 | ||
| Output: [0,1,1] | ||
| Explanation: | ||
| 0 --> 0 | ||
| 1 --> 1 | ||
| 2 --> 10 | ||
| ``` | ||
|
|
||
| ``` | ||
| Example 2: | ||
| Input: n = 5 | ||
| Output: [0,1,1,2,1,2] | ||
| Explanation: | ||
| 0 --> 0 | ||
| 1 --> 1 | ||
| 2 --> 10 | ||
| 3 --> 11 | ||
| 4 --> 100 | ||
| 5 --> 101 | ||
| ``` | ||
|
|
||
| ## Constraints | ||
|
|
||
| - 0 <= `n` <= 10^5 | ||
|
|
||
| ## Solution | ||
|
|
||
| This solution uses a bottom-up dynamic programming approach to solve the problem. | ||
| The key to this problem lies in the fact that any binary number can be broken down into two parts: the least-significant | ||
| (rightmost bit), and the rest of the bits. The rest of the bits can be expressed as the binary number divided by 2 | ||
| (rounded down), or `i >> 1`. | ||
|
|
||
| For example: | ||
| - 4 in binary = 100 | ||
| - rightmost bit = 0 | ||
| - rest of bits = 10, which is also (4 // 2) = 2 in binary. | ||
|
|
||
| When the number is odd, | ||
| - 5 in binary = 101 | ||
| - rightmost bit = 1 | ||
| - rest of bits = 10, which is also (5 // 2) = 2 in binary. | ||
|
|
||
| in the binary representation of i is that number plus 1 if the rightmost bit is 1. We can tell if the last significant | ||
| bit is 1 by checking if it is odd. | ||
|
|
||
BrianLusina marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| As an example, we know that the number of 1's in 2 is 1. This information can be used to calculate the number of 1's in 4. | ||
| The number of 1's in 4 is the number of 1's in 2 plus 0, because 4 is even. | ||
|
|
||
| This establishes a recurrence relationship between the number of 1's in the binary representation of i and the number of | ||
| 1's in the binary representation of i // 2: if count[i] is the number of 1's in the binary representation of i, then | ||
| count[i] = count[i // 2] + (i % 2). | ||
|
|
||
| With the recurrence relationship established, we can now solve the problem using a bottom-up dynamic programming approach. | ||
| We start with the base case dp[0] = 0, and then build up the solution for dp[i] for i from 1 to n. | ||
|
|
||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
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,20 @@ | ||
| from typing import List | ||
|
|
||
|
|
||
| def count_bits(n: int) -> List[int]: | ||
| """ | ||
| Counts the number of 1 bits in the given integer provided returning a list where count[i] stores the count of '1' | ||
| bits in the binary form of i. | ||
| Args: | ||
| n(int): integer | ||
| Returns: | ||
| list: count of 1 bits where each index contains the count of 1 bits | ||
| """ | ||
| dp = [0] * (n + 1) | ||
|
|
||
| for i in range(1, n + 1): | ||
| # this can also be solved as which is faster in Python | ||
| # dp[i] = dp[i >> 1] + (i & 1) | ||
| dp[i] = dp[i // 2] + (i % 2) | ||
|
|
||
| return dp |
Binary file added
BIN
+36.1 KB
.../dynamic_programming/countingbits/images/solutions/counting_bits_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
+40 KB
...dynamic_programming/countingbits/images/solutions/counting_bits_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
+52.2 KB
...dynamic_programming/countingbits/images/solutions/counting_bits_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
+33.1 KB
...dynamic_programming/countingbits/images/solutions/counting_bits_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
+42.3 KB
.../dynamic_programming/countingbits/images/solutions/counting_bits_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
+53.7 KB
.../dynamic_programming/countingbits/images/solutions/counting_bits_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
+44.2 KB
.../dynamic_programming/countingbits/images/solutions/counting_bits_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
+52.9 KB
.../dynamic_programming/countingbits/images/solutions/counting_bits_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
+40.8 KB
.../dynamic_programming/countingbits/images/solutions/counting_bits_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
+52.9 KB
.../dynamic_programming/countingbits/images/solutions/counting_bits_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
+44.7 KB
.../dynamic_programming/countingbits/images/solutions/counting_bits_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
+56.6 KB
.../dynamic_programming/countingbits/images/solutions/counting_bits_solution_9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions
24
algorithms/dynamic_programming/countingbits/test_counting_bits.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,24 @@ | ||
| import unittest | ||
| from typing import List | ||
| from parameterized import parameterized | ||
| from algorithms.dynamic_programming.countingbits import count_bits | ||
|
|
||
| COUNTING_BITS_TEST_CASES = [ | ||
| (6, [0, 1, 1, 2, 1, 2, 2]), | ||
| (2, [0, 1, 1]), | ||
| (5, [0, 1, 1, 2, 1, 2]), | ||
| (0, [0]), | ||
| (7, [0, 1, 1, 2, 1, 2, 2, 3]), | ||
| (10, [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2]), | ||
| ] | ||
|
|
||
|
|
||
| class CountingBitsTestCase(unittest.TestCase): | ||
| @parameterized.expand(COUNTING_BITS_TEST_CASES) | ||
| def test_counting_bits(self, n: int, expected: List[int]): | ||
| actual = count_bits(n) | ||
| self.assertEqual(expected, actual) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| unittest.main() |
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,29 @@ | ||
| # Find K Closest Elements | ||
|
|
||
| Given a sorted array nums, a target value target, and an integer k, find the k closest elements to target in the array, | ||
| where "closest" is the absolute difference between each element and target. Return these elements in an array, sorted in | ||
| ascending order. | ||
|
|
||
| ## Examples | ||
|
|
||
| ```text | ||
| nums = [-1, 0, 1, 4, 6] | ||
| target = 1 | ||
| k = 3 | ||
| Output | ||
| [-1, 0, 1] | ||
| Explanation | ||
| Explanation: -1 is 2 away from 1, 0 is 1 away from 1, and 1 is 0 away from 1. All other elements are more than 2 away. | ||
BrianLusina marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Since we need to return the elements in ascending order, the answer is [-1, 0, 1] | ||
| ``` | ||
|
|
||
| ```text | ||
| nums = [5, 6, 7, 8, 9] | ||
| target = 10 | ||
| k = 2 | ||
| Output: | ||
| [8, 9] | ||
| ``` | ||
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,18 @@ | ||
| from typing import List | ||
| import heapq | ||
|
|
||
|
|
||
| def k_closest(nums: List[int], k: int, target: int): | ||
| heap = [] | ||
|
|
||
| for num in nums: | ||
| diff = abs(num - target) | ||
|
|
||
| if len(heap) < k: | ||
| heapq.heappush(heap, (-diff, num)) | ||
| elif diff < -heap[0][0]: | ||
| heapq.heappushpop(heap, (-diff, num)) | ||
|
|
||
| distances = [pair[1] for pair in heap] | ||
| distances.sort() | ||
| return distances |
26 changes: 26 additions & 0 deletions
26
algorithms/heap/kclosestelements/test_find_k_closest_elements.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,26 @@ | ||
| import unittest | ||
| from typing import List | ||
| from parameterized import parameterized | ||
| from algorithms.heap.kclosestelements import k_closest | ||
|
|
||
| K_CLOSEST_ELEMENTS_TEST_CASES = [ | ||
| ([1, 2, 3, 4, 5], 4, 3, [1, 2, 3, 4]), | ||
| ([1, 3, 5, 8, 10], 2, 5, [3, 5]), | ||
| ([3, 4, 7, 10, 15], 3, 8, [4, 7, 10]), | ||
| ([5, 6, 7, 8, 9], 3, 7, [6, 7, 8]), | ||
| ([1, 1, 1, 10, 10, 10], 1, 9, [10]), | ||
| ([1, 2, 3, 4, 5], 2, 6, [4, 5]), | ||
| ] | ||
|
|
||
|
|
||
| class KClosestElementsTestCase(unittest.TestCase): | ||
| @parameterized.expand(K_CLOSEST_ELEMENTS_TEST_CASES) | ||
| def test_k_closest_elements( | ||
| self, nums: List[int], k: int, target: int, expected: List[int] | ||
| ): | ||
| actual = k_closest(nums, k, target) | ||
| self.assertEqual(expected, actual) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| unittest.main() |
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,18 @@ | ||
| # Merge K Sorted Lists | ||
|
|
||
| Given k linked lists, each sorted in ascending order, in a list lists, write a function to merge the input lists into | ||
| one sorted linked list. | ||
|
|
||
| ## Examples | ||
|
|
||
| ```text | ||
| lists = [[3,4,6],[2,3,5],[-1,6]] | ||
| 3 -> 4 -> 6 | ||
| 2 -> 3 -> 5 | ||
| -1 -> 6 | ||
|
|
||
| Output | ||
| [-1,2,3,3,4,5,6,6] | ||
|
|
||
| -1 -> 2 -> 3 -> 3 -> 4 -> 5 -> 6 -> 6 | ||
| ``` |
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,53 @@ | ||
| from typing import List | ||
| import heapq | ||
|
|
||
|
|
||
| def merge_k_lists(lists: List[List[int]]) -> List[int]: | ||
| """ | ||
| Merges k sorted lists into one list | ||
| Args: | ||
| lists(list): list of lists | ||
| Returns: | ||
| list: Combined list from the input list that is sorted | ||
| """ | ||
| # Validate that the input provided is not empty. If it is empty, return an empty list. Nothing more to do here | ||
| if not lists: | ||
| return [] | ||
|
|
||
| # Check if any of the lists provided is empty. If we have an empty list, we return, as there is nothing more to do | ||
| has_non_empty = any(lst for lst in lists) | ||
| if not has_non_empty: | ||
| return [] | ||
|
|
||
| # Initialize our heap. This will be used to keep the lowest value from each list at the root of the heap. Whenever | ||
| # a value is popped from the root, the next value is added to the list and if it is the lowest value it will be | ||
| # at the root of the heap | ||
| min_heap = [] | ||
|
|
||
| # We will iterate through the list storing only the first values from each list, including the list index and the | ||
| # element index which we will use to iterate through a given list. The list index will be used to iterate through | ||
| # the provided lists | ||
| for idx, lst in enumerate(lists): | ||
| if lst: | ||
| value, list_index, element_index = lst[0], idx, 0 | ||
| heapq.heappush(min_heap, (value, list_index, element_index)) | ||
|
|
||
| # Result will store the final output | ||
| result: List[int] = [] | ||
|
|
||
| # While we still have elements in the heap | ||
| while min_heap: | ||
| # We get the top element from the heap | ||
| value, list_index, element_index = heapq.heappop(min_heap) | ||
| # Add the value to the result, at this point, we know this is the smallest value in the lists of lists | ||
| result.append(value) | ||
|
|
||
| # We check if the element index is less than the current list it can be found in. This means that there are | ||
| # still other elements within this list | ||
| if element_index + 1 < len(lists[list_index]): | ||
| # We add the next value to the heap | ||
| next_value = lists[list_index][element_index + 1] | ||
| heapq.heappush(min_heap, (next_value, list_index, element_index + 1)) | ||
|
|
||
| # Return the result | ||
| return result |
24 changes: 24 additions & 0 deletions
24
algorithms/heap/mergeksortedlists/test_merge_k_sorted_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,24 @@ | ||
| import unittest | ||
| from typing import List | ||
| from parameterized import parameterized | ||
| from algorithms.heap.mergeksortedlists import merge_k_lists | ||
|
|
||
| MERGE_K_LISTS_TEST_CASES = [ | ||
| ([[3, 4, 6], [2, 3, 5], [-1, 6]], [-1, 2, 3, 3, 4, 5, 6, 6]), | ||
| ([[2, 4, 6], [1, 3, 5]], [1, 2, 3, 4, 5, 6]), | ||
| ([[1, 4, 5], [1, 3, 4], [2, 6]], [1, 1, 2, 3, 4, 4, 5, 6]), | ||
| ([], []), | ||
| ([[]], []), | ||
| ([[1, 2, 3]], [1, 2, 3]), | ||
| ] | ||
|
|
||
|
|
||
| class MergeKListsTestCase(unittest.TestCase): | ||
| @parameterized.expand(MERGE_K_LISTS_TEST_CASES) | ||
| def test_merge_k_lists(self, lists: List[List[int]], expected: List[int]): | ||
| actual = merge_k_lists(lists) | ||
| 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.