diff --git a/.cursor/.dev/update_tags.json b/.cursor/.dev/update_tags.json new file mode 100644 index 0000000..503c7c3 --- /dev/null +++ b/.cursor/.dev/update_tags.json @@ -0,0 +1,17 @@ +{ + "neetcode-150": [ + "binary_tree_maximum_path_sum", + "find_minimum_in_rotated_sorted_array", + "number_of_1_bits", + "reorder_list", + "reverse_bits" + ], + "algo-master-75": ["binary_tree_maximum_path_sum"], + "blind-75": [ + "binary_tree_maximum_path_sum", + "find_minimum_in_rotated_sorted_array", + "number_of_1_bits", + "reorder_list", + "reverse_bits" + ] +} diff --git a/Makefile b/Makefile index 5d3e60d..221c972 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ PYTHON_VERSION = 3.13 -PROBLEM ?= same_tree +PROBLEM ?= number_of_1_bits FORCE ?= 0 COMMA := , diff --git a/leetcode/binary_tree_maximum_path_sum/README.md b/leetcode/binary_tree_maximum_path_sum/README.md new file mode 100644 index 0000000..1b0b7ef --- /dev/null +++ b/leetcode/binary_tree_maximum_path_sum/README.md @@ -0,0 +1,42 @@ +# Binary Tree Maximum Path Sum + +**Difficulty:** Hard +**Topics:** Dynamic Programming, Tree, Depth-First Search, Binary Tree +**Tags:** blind-75 + +**LeetCode:** [Problem 124](https://leetcode.com/problems/binary-tree-maximum-path-sum/description/) + +## Problem Description + +A **path** in a binary tree is a sequence of nodes where each pair of adjacent nodes in the sequence has an edge connecting them. A node can only appear in the sequence **at most once**. Note that the path does not need to pass through the root. + +The **path sum** of a path is the sum of the node's values in the path. + +Given the `root` of a binary tree, return _the maximum **path sum** of any **non-empty** path_. + +## Examples + +### Example 1: + +![Example 1](https://assets.leetcode.com/uploads/2020/10/13/exx1.jpg) + +``` +Input: root = [1,2,3] +Output: 6 +Explanation: The optimal path is 2 -> 1 -> 3 with a path sum of 2 + 1 + 3 = 6. +``` + +### Example 2: + +![Example 2](https://assets.leetcode.com/uploads/2020/10/13/exx2.jpg) + +``` +Input: root = [-10,9,20,null,null,15,7] +Output: 42 +Explanation: The optimal path is 15 -> 20 -> 7 with a path sum of 15 + 20 + 7 = 42. +``` + +## Constraints + +- The number of nodes in the tree is in the range [1, 3 * 10^4]. +- -1000 <= Node.val <= 1000 diff --git a/leetcode/binary_tree_maximum_path_sum/__init__.py b/leetcode/binary_tree_maximum_path_sum/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/leetcode/binary_tree_maximum_path_sum/helpers.py b/leetcode/binary_tree_maximum_path_sum/helpers.py new file mode 100644 index 0000000..02f222a --- /dev/null +++ b/leetcode/binary_tree_maximum_path_sum/helpers.py @@ -0,0 +1,12 @@ +from leetcode_py import TreeNode + + +def run_max_path_sum(solution_class: type, root_list: list[int | None]): + root = TreeNode[int].from_list(root_list) + implementation = solution_class() + return implementation.max_path_sum(root) + + +def assert_max_path_sum(result: int, expected: int) -> bool: + assert result == expected + return True diff --git a/leetcode/binary_tree_maximum_path_sum/playground.py b/leetcode/binary_tree_maximum_path_sum/playground.py new file mode 100644 index 0000000..c24c7bf --- /dev/null +++ b/leetcode/binary_tree_maximum_path_sum/playground.py @@ -0,0 +1,29 @@ +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.17.3 +# kernelspec: +# display_name: leetcode-py-py3.13 +# language: python +# name: python3 +# --- + +# %% +from helpers import assert_max_path_sum, run_max_path_sum +from solution import Solution + +# %% +# Example test case +root_list: list[int | None] = [1, 2, 3] +expected: int = 6 + +# %% +result = run_max_path_sum(Solution, root_list) +result + +# %% +assert_max_path_sum(result, expected) diff --git a/leetcode/binary_tree_maximum_path_sum/solution.py b/leetcode/binary_tree_maximum_path_sum/solution.py new file mode 100644 index 0000000..ae3d927 --- /dev/null +++ b/leetcode/binary_tree_maximum_path_sum/solution.py @@ -0,0 +1,48 @@ +from leetcode_py import TreeNode + + +class Solution: + + # Time: O(n) where n is the number of nodes + # Space: O(h) where h is the height of the tree (recursion stack) + def max_path_sum(self, root: TreeNode[int] | None) -> int: + """ + Find the maximum path sum in a binary tree. + + A path is a sequence of nodes where each pair of adjacent nodes + has an edge connecting them. A node can only appear once in the path. + The path doesn't need to pass through the root. + + Uses DFS with post-order traversal to calculate: + 1. Maximum path sum that can be extended upward from current node + 2. Maximum path sum that includes current node as the highest point + """ + if not root: + return 0 + + max_sum = float("-inf") + + def dfs(node: TreeNode[int] | None) -> int: + nonlocal max_sum + + if not node: + return 0 + + # Get maximum path sum from left and right subtrees + # If negative, we don't include them (take 0 instead) + left_max = max(0, dfs(node.left)) + right_max = max(0, dfs(node.right)) + + # Current path sum if this node is the highest point + # (left path + current node + right path) + current_path_sum = node.val + left_max + right_max + + # Update global maximum + max_sum = max(max_sum, current_path_sum) + + # Return maximum path sum that can be extended upward + # (either left or right path + current node) + return node.val + max(left_max, right_max) + + dfs(root) + return int(max_sum) diff --git a/leetcode/binary_tree_maximum_path_sum/test_solution.py b/leetcode/binary_tree_maximum_path_sum/test_solution.py new file mode 100644 index 0000000..441a46a --- /dev/null +++ b/leetcode/binary_tree_maximum_path_sum/test_solution.py @@ -0,0 +1,36 @@ +import pytest + +from leetcode_py import logged_test + +from .helpers import assert_max_path_sum, run_max_path_sum +from .solution import Solution + + +class TestBinaryTreeMaximumPathSum: + def setup_method(self): + self.solution = Solution() + + @logged_test + @pytest.mark.parametrize( + "root_list, expected", + [ + ([1, 2, 3], 6), + ([-10, 9, 20, None, None, 15, 7], 42), + ([1], 1), + ([-3], -3), + ([1, -2, 3], 4), + ([5, 4, 8, 11, None, 13, 4, 7, 2, None, None, None, 1], 48), + ([1, 2, 3, 4, 5], 11), + ([-1, -2, -3], -1), + ([1, -1, 2], 3), + ([1, 2, -3, 4, 5], 11), + ([1, 2, 3, None, None, 4, 5], 12), + ([-1, 2, 3], 4), + ([1, -2, -3, 1, 3, -2, None, -1], 3), + ([2, -1], 2), + ([1, 2], 3), + ], + ) + def test_max_path_sum(self, root_list: list[int | None], expected: int): + result = run_max_path_sum(Solution, root_list) + assert_max_path_sum(result, expected) diff --git a/leetcode/find_minimum_in_rotated_sorted_array/README.md b/leetcode/find_minimum_in_rotated_sorted_array/README.md new file mode 100644 index 0000000..f739190 --- /dev/null +++ b/leetcode/find_minimum_in_rotated_sorted_array/README.md @@ -0,0 +1,54 @@ +# Find Minimum in Rotated Sorted Array + +**Difficulty:** Medium +**Topics:** Array, Binary Search +**Tags:** blind-75 + +**LeetCode:** [Problem 153](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/description/) + +## Problem Description + +Suppose an array of length `n` sorted in ascending order is **rotated** between `1` and `n` times. For example, the array `nums = [0,1,2,4,5,6,7]` might become: + +- `[4,5,6,7,0,1,2]` if it was rotated `4` times. +- `[0,1,2,4,5,6,7]` if it was rotated `7` times. + +Notice that **rotating** an array `[a[0], a[1], a[2], ..., a[n-1]]` 1 time results in the array `[a[n-1], a[0], a[1], a[2], ..., a[n-2]]`. + +Given the sorted rotated array `nums` of **unique** elements, return _the minimum element of this array_. + +You must write an algorithm that runs in O(log n) time. + +## Examples + +### Example 1: + +``` +Input: nums = [3,4,5,1,2] +Output: 1 +Explanation: The original array was [1,2,3,4,5] rotated 3 times. +``` + +### Example 2: + +``` +Input: nums = [4,5,6,7,0,1,2] +Output: 0 +Explanation: The original array was [0,1,2,4,5,6,7] and it was rotated 4 times. +``` + +### Example 3: + +``` +Input: nums = [11,13,15,17] +Output: 11 +Explanation: The original array was [11,13,15,17] and it was rotated 4 times. +``` + +## Constraints + +- n == nums.length +- 1 <= n <= 5000 +- -5000 <= nums[i] <= 5000 +- All the integers of nums are **unique**. +- nums is sorted and rotated between 1 and n times. diff --git a/leetcode/find_minimum_in_rotated_sorted_array/__init__.py b/leetcode/find_minimum_in_rotated_sorted_array/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/leetcode/find_minimum_in_rotated_sorted_array/helpers.py b/leetcode/find_minimum_in_rotated_sorted_array/helpers.py new file mode 100644 index 0000000..2327731 --- /dev/null +++ b/leetcode/find_minimum_in_rotated_sorted_array/helpers.py @@ -0,0 +1,8 @@ +def run_find_min(solution_class: type, nums: list[int]): + implementation = solution_class() + return implementation.find_min(nums) + + +def assert_find_min(result: int, expected: int) -> bool: + assert result == expected + return True diff --git a/leetcode/find_minimum_in_rotated_sorted_array/playground.py b/leetcode/find_minimum_in_rotated_sorted_array/playground.py new file mode 100644 index 0000000..1255b05 --- /dev/null +++ b/leetcode/find_minimum_in_rotated_sorted_array/playground.py @@ -0,0 +1,29 @@ +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.17.3 +# kernelspec: +# display_name: leetcode-py-py3.13 +# language: python +# name: python3 +# --- + +# %% +from helpers import assert_find_min, run_find_min +from solution import Solution + +# %% +# Example test case +nums: list[int] = [3, 4, 5, 1, 2] +expected: int = 1 + +# %% +result = run_find_min(Solution, nums) +result + +# %% +assert_find_min(result, expected) diff --git a/leetcode/find_minimum_in_rotated_sorted_array/solution.py b/leetcode/find_minimum_in_rotated_sorted_array/solution.py new file mode 100644 index 0000000..aeaef96 --- /dev/null +++ b/leetcode/find_minimum_in_rotated_sorted_array/solution.py @@ -0,0 +1,37 @@ +class Solution: + + # Time: O(log n) - binary search + # Space: O(1) - only using constant extra space + def find_min(self, nums: list[int]) -> int: + """ + Find the minimum element in a rotated sorted array using binary search. + + The key insight is that in a rotated sorted array, one half is always sorted. + We can determine which half contains the minimum by comparing the middle + element with the rightmost element. + + Algorithm: + 1. If nums[left] < nums[right], the array is not rotated, return nums[left] + 2. Otherwise, find the rotation point using binary search + 3. The minimum is always at the rotation point + """ + left, right = 0, len(nums) - 1 + + # If the array is not rotated, the first element is the minimum + if nums[left] < nums[right]: + return nums[left] + + # Binary search to find the rotation point + while left < right: + mid = left + (right - left) // 2 + + # If mid element is greater than right element, + # the rotation point is in the right half + if nums[mid] > nums[right]: + left = mid + 1 + else: + # If mid element is less than or equal to right element, + # the rotation point is in the left half (including mid) + right = mid + + return nums[left] diff --git a/leetcode/find_minimum_in_rotated_sorted_array/test_solution.py b/leetcode/find_minimum_in_rotated_sorted_array/test_solution.py new file mode 100644 index 0000000..f19f92b --- /dev/null +++ b/leetcode/find_minimum_in_rotated_sorted_array/test_solution.py @@ -0,0 +1,39 @@ +import pytest + +from leetcode_py import logged_test + +from .helpers import assert_find_min, run_find_min +from .solution import Solution + + +class TestFindMinimumInRotatedSortedArray: + def setup_method(self): + self.solution = Solution() + + @logged_test + @pytest.mark.parametrize( + "nums, expected", + [ + ([3, 4, 5, 1, 2], 1), + ([4, 5, 6, 7, 0, 1, 2], 0), + ([11, 13, 15, 17], 11), + ([1], 1), + ([2, 1], 1), + ([1, 2, 3], 1), + ([3, 1, 2], 1), + ([2, 3, 1], 1), + ([4, 5, 6, 7, 8, 1, 2, 3], 1), + ([5, 6, 7, 8, 9, 10, 1, 2, 3, 4], 1), + ([6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5], 1), + ([7, 8, 9, 10, 11, 12, 13, 14, 1, 2, 3, 4, 5, 6], 1), + ([8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7], 1), + ([9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8], 1), + ( + [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9], + 1, + ), + ], + ) + def test_find_min(self, nums: list[int], expected: int): + result = run_find_min(Solution, nums) + assert_find_min(result, expected) diff --git a/leetcode/number_of_1_bits/README.md b/leetcode/number_of_1_bits/README.md new file mode 100644 index 0000000..57de621 --- /dev/null +++ b/leetcode/number_of_1_bits/README.md @@ -0,0 +1,44 @@ +# Number of 1 Bits + +**Difficulty:** Easy +**Topics:** Divide and Conquer, Bit Manipulation +**Tags:** blind-75 + +**LeetCode:** [Problem 191](https://leetcode.com/problems/number-of-1-bits/description/) + +## Problem Description + +Given a positive integer `n`, write a function that returns the number of set bits in its binary representation (also known as the Hamming weight). + +## Examples + +### Example 1: + +``` +Input: n = 11 +Output: 3 +Explanation: +The input binary string 1011 has a total of three set bits. +``` + +### Example 2: + +``` +Input: n = 128 +Output: 1 +Explanation: +The input binary string 10000000 has a total of one set bit. +``` + +### Example 3: + +``` +Input: n = 2147483645 +Output: 30 +Explanation: +The input binary string 1111111111111111111111111111101 has a total of thirty set bits. +``` + +## Constraints + +- 1 <= n <= 2^31 - 1 diff --git a/leetcode/number_of_1_bits/__init__.py b/leetcode/number_of_1_bits/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/leetcode/number_of_1_bits/helpers.py b/leetcode/number_of_1_bits/helpers.py new file mode 100644 index 0000000..b1dd9dd --- /dev/null +++ b/leetcode/number_of_1_bits/helpers.py @@ -0,0 +1,8 @@ +def run_hamming_weight(solution_class: type, n: int): + implementation = solution_class() + return implementation.hamming_weight(n) + + +def assert_hamming_weight(result: int, expected: int) -> bool: + assert result == expected + return True diff --git a/leetcode/number_of_1_bits/playground.py b/leetcode/number_of_1_bits/playground.py new file mode 100644 index 0000000..577444e --- /dev/null +++ b/leetcode/number_of_1_bits/playground.py @@ -0,0 +1,29 @@ +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.17.3 +# kernelspec: +# display_name: leetcode-py-py3.13 +# language: python +# name: python3 +# --- + +# %% +from helpers import assert_hamming_weight, run_hamming_weight +from solution import Solution + +# %% +# Example test case +n = 11 +expected = 3 + +# %% +result = run_hamming_weight(Solution, n) +result + +# %% +assert_hamming_weight(result, expected) diff --git a/leetcode/number_of_1_bits/solution.py b/leetcode/number_of_1_bits/solution.py new file mode 100644 index 0000000..19f2f5c --- /dev/null +++ b/leetcode/number_of_1_bits/solution.py @@ -0,0 +1,20 @@ +class Solution: + + # Time: O(1) - at most 32 iterations (number of bits in int) + # Space: O(1) - only using constant extra space + def hamming_weight(self, n: int) -> int: + """ + Count the number of set bits (1s) in the binary representation of n. + + Uses the Brian Kernighan's algorithm: + n & (n-1) removes the rightmost set bit from n. + We keep doing this until n becomes 0, counting each iteration. + + This is more efficient than checking each bit individually + because it only iterates for the number of set bits, not all bits. + """ + count = 0 + while n: + count += 1 + n &= n - 1 # Remove the rightmost set bit + return count diff --git a/leetcode/number_of_1_bits/test_solution.py b/leetcode/number_of_1_bits/test_solution.py new file mode 100644 index 0000000..7bb9059 --- /dev/null +++ b/leetcode/number_of_1_bits/test_solution.py @@ -0,0 +1,37 @@ +import pytest + +from leetcode_py import logged_test + +from .helpers import assert_hamming_weight, run_hamming_weight +from .solution import Solution + + +class TestNumberOf1Bits: + def setup_method(self): + self.solution = Solution() + + @logged_test + @pytest.mark.parametrize( + "n, expected", + [ + (11, 3), + (128, 1), + (2147483645, 30), + (0, 0), + (1, 1), + (2, 1), + (3, 2), + (4, 1), + (5, 2), + (6, 2), + (7, 3), + (8, 1), + (15, 4), + (16, 1), + (255, 8), + (256, 1), + ], + ) + def test_hamming_weight(self, n: int, expected: int): + result = run_hamming_weight(Solution, n) + assert_hamming_weight(result, expected) diff --git a/leetcode/reorder_list/README.md b/leetcode/reorder_list/README.md new file mode 100644 index 0000000..559ea03 --- /dev/null +++ b/leetcode/reorder_list/README.md @@ -0,0 +1,44 @@ +# Reorder List + +**Difficulty:** Medium +**Topics:** Linked List, Two Pointers, Stack, Recursion +**Tags:** blind-75 + +**LeetCode:** [Problem 143](https://leetcode.com/problems/reorder-list/description/) + +## Problem Description + +You are given the head of a singly linked-list. The list can be represented as: + +L0 → L1 → … → Ln - 1 → Ln + +_Reorder the list to be on the following form:_ + +L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … + +You may not modify the values in the list's nodes. Only nodes themselves may be changed. + +## Examples + +### Example 1: + +![Example 1](https://assets.leetcode.com/uploads/2021/03/04/reorder1linked-list.jpg) + +``` +Input: head = [1,2,3,4] +Output: [1,4,2,3] +``` + +### Example 2: + +![Example 2](https://assets.leetcode.com/uploads/2021/03/09/reorder2-linked-list.jpg) + +``` +Input: head = [1,2,3,4,5] +Output: [1,5,2,4,3] +``` + +## Constraints + +- The number of nodes in the list is in the range [1, 5 * 10^4]. +- 1 <= Node.val <= 1000 diff --git a/leetcode/reorder_list/__init__.py b/leetcode/reorder_list/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/leetcode/reorder_list/helpers.py b/leetcode/reorder_list/helpers.py new file mode 100644 index 0000000..c687302 --- /dev/null +++ b/leetcode/reorder_list/helpers.py @@ -0,0 +1,13 @@ +from leetcode_py import ListNode + + +def run_reorder_list(solution_class: type, head_list: list[int]): + head = ListNode[int].from_list(head_list) + implementation = solution_class() + implementation.reorder_list(head) + return head.to_list() if head else [] + + +def assert_reorder_list(result: list[int], expected: list[int]) -> bool: + assert result == expected + return True diff --git a/leetcode/reorder_list/playground.py b/leetcode/reorder_list/playground.py new file mode 100644 index 0000000..147f4f7 --- /dev/null +++ b/leetcode/reorder_list/playground.py @@ -0,0 +1,29 @@ +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.17.3 +# kernelspec: +# display_name: leetcode-py-py3.13 +# language: python +# name: python3 +# --- + +# %% +from helpers import assert_reorder_list, run_reorder_list +from solution import Solution + +# %% +# Example test case +head_list: list[int] = [1, 2, 3, 4] +expected: list[int] = [1, 4, 2, 3] + +# %% +result = run_reorder_list(Solution, head_list) +result + +# %% +assert_reorder_list(result, expected) diff --git a/leetcode/reorder_list/solution.py b/leetcode/reorder_list/solution.py new file mode 100644 index 0000000..bb2d635 --- /dev/null +++ b/leetcode/reorder_list/solution.py @@ -0,0 +1,56 @@ +from leetcode_py import ListNode + + +class Solution: + + # Time: O(n) where n is the number of nodes + # Space: O(1) - only using constant extra space + def reorder_list(self, head: ListNode[int] | None) -> None: + """ + Reorder a linked list in-place: L0→L1→...→Ln-1→Ln becomes L0→Ln→L1→Ln-1→L2→Ln-2→... + + Algorithm: + 1. Find the middle of the list using slow/fast pointers + 2. Reverse the second half of the list + 3. Merge the first half and reversed second half alternately + + This approach uses O(1) space and O(n) time. + """ + if not head or not head.next: + return + + # Step 1: Find the middle of the list + slow = fast = head + while fast.next and fast.next.next: + assert slow.next + slow = slow.next + fast = fast.next.next + + # Split the list into two halves + second_half = slow.next + slow.next = None # Break the connection + + # Step 2: Reverse the second half + prev = None + current = second_half + while current: + next_temp = current.next + current.next = prev + prev = current + current = next_temp + second_half = prev + + # Step 3: Merge the two halves alternately + first_half = head + while second_half: + # Store next nodes + first_next = first_half.next + second_next = second_half.next + + # Reorder: first -> second -> first_next + first_half.next = second_half + second_half.next = first_next + + # Move to next nodes + first_half = first_next # type: ignore[assignment] + second_half = second_next diff --git a/leetcode/reorder_list/test_solution.py b/leetcode/reorder_list/test_solution.py new file mode 100644 index 0000000..3d76a38 --- /dev/null +++ b/leetcode/reorder_list/test_solution.py @@ -0,0 +1,48 @@ +import pytest + +from leetcode_py import logged_test + +from .helpers import assert_reorder_list, run_reorder_list +from .solution import Solution + + +class TestReorderList: + def setup_method(self): + self.solution = Solution() + + @logged_test + @pytest.mark.parametrize( + "head_list, expected", + [ + ([1, 2, 3, 4], [1, 4, 2, 3]), + ([1, 2, 3, 4, 5], [1, 5, 2, 4, 3]), + ([1], [1]), + ([1, 2], [1, 2]), + ([1, 2, 3], [1, 3, 2]), + ([1, 2, 3, 4, 5, 6], [1, 6, 2, 5, 3, 4]), + ([1, 2, 3, 4, 5, 6, 7], [1, 7, 2, 6, 3, 5, 4]), + ([1, 2, 3, 4, 5, 6, 7, 8], [1, 8, 2, 7, 3, 6, 4, 5]), + ([1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 9, 2, 8, 3, 7, 4, 6, 5]), + ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 10, 2, 9, 3, 8, 4, 7, 5, 6]), + ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [1, 11, 2, 10, 3, 9, 4, 8, 5, 7, 6]), + ( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], + [1, 12, 2, 11, 3, 10, 4, 9, 5, 8, 6, 7], + ), + ( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], + [1, 13, 2, 12, 3, 11, 4, 10, 5, 9, 6, 8, 7], + ), + ( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], + [1, 14, 2, 13, 3, 12, 4, 11, 5, 10, 6, 9, 7, 8], + ), + ( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + [1, 15, 2, 14, 3, 13, 4, 12, 5, 11, 6, 10, 7, 9, 8], + ), + ], + ) + def test_reorder_list(self, head_list: list[int], expected: list[int]): + result = run_reorder_list(Solution, head_list) + assert_reorder_list(result, expected) diff --git a/leetcode/reverse_bits/README.md b/leetcode/reverse_bits/README.md new file mode 100644 index 0000000..628d89c --- /dev/null +++ b/leetcode/reverse_bits/README.md @@ -0,0 +1,46 @@ +# Reverse Bits + +**Difficulty:** Easy +**Topics:** Divide and Conquer, Bit Manipulation +**Tags:** blind-75 + +**LeetCode:** [Problem 190](https://leetcode.com/problems/reverse-bits/description/) + +## Problem Description + +Reverse bits of a given 32 bits signed integer. + +## Examples + +### Example 1: + +``` +Input: n = 43261596 +Output: 964176192 +Explanation: + +| Integer | Binary | +|------------|-------------------------------------| +| 43261596 | 00000010100101000001111010011100 | +| 964176192 | 00111001011110000010100101000000 | +``` + +### Example 2: + +``` +Input: n = 2147483644 +Output: 1073741822 +Explanation: + +| Integer | Binary | +|-------------|-------------------------------------| +| 2147483644 | 01111111111111111111111111111100 | +| 1073741822 | 00111111111111111111111111111110 | +``` + +## Constraints + +- 0 <= n <= 2^31 - 2 +- n is even. + +**Follow up:** If this function is called many times, how would you optimize it? diff --git a/leetcode/reverse_bits/__init__.py b/leetcode/reverse_bits/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/leetcode/reverse_bits/helpers.py b/leetcode/reverse_bits/helpers.py new file mode 100644 index 0000000..dd94311 --- /dev/null +++ b/leetcode/reverse_bits/helpers.py @@ -0,0 +1,8 @@ +def run_reverse_bits(solution_class: type, n: int): + implementation = solution_class() + return implementation.reverse_bits(n) + + +def assert_reverse_bits(result: int, expected: int) -> bool: + assert result == expected + return True diff --git a/leetcode/reverse_bits/playground.py b/leetcode/reverse_bits/playground.py new file mode 100644 index 0000000..5daf7a8 --- /dev/null +++ b/leetcode/reverse_bits/playground.py @@ -0,0 +1,29 @@ +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.17.3 +# kernelspec: +# display_name: leetcode-py-py3.13 +# language: python +# name: python3 +# --- + +# %% +from helpers import assert_reverse_bits, run_reverse_bits +from solution import Solution + +# %% +# Example test case +n: int = 43261596 +expected: int = 964176192 + +# %% +result = run_reverse_bits(Solution, n) +result + +# %% +assert_reverse_bits(result, expected) diff --git a/leetcode/reverse_bits/solution.py b/leetcode/reverse_bits/solution.py new file mode 100644 index 0000000..bc11d9d --- /dev/null +++ b/leetcode/reverse_bits/solution.py @@ -0,0 +1,25 @@ +class Solution: + + # Time: O(1) - always 32 iterations + # Space: O(1) - only using constant extra space + def reverse_bits(self, n: int) -> int: + """ + Reverse the bits of a 32-bit unsigned integer. + + Algorithm: + 1. Initialize result to 0 + 2. For each of the 32 bits: + - Extract the rightmost bit of n using (n & 1) + - Add it to the result at the appropriate position + - Right shift n to get the next bit + - Left shift result to make room for the next bit + 3. Return the result + + This approach is optimal for single calls. For multiple calls, + we could use a lookup table for optimization. + """ + result = 0 + for _ in range(32): + result = (result << 1) | (n & 1) + n >>= 1 + return result diff --git a/leetcode/reverse_bits/test_solution.py b/leetcode/reverse_bits/test_solution.py new file mode 100644 index 0000000..a29af7f --- /dev/null +++ b/leetcode/reverse_bits/test_solution.py @@ -0,0 +1,37 @@ +import pytest + +from leetcode_py import logged_test + +from .helpers import assert_reverse_bits, run_reverse_bits +from .solution import Solution + + +class TestReverseBits: + def setup_method(self): + self.solution = Solution() + + @logged_test + @pytest.mark.parametrize( + "n, expected", + [ + (43261596, 964176192), + (2147483644, 1073741822), + (0, 0), + (1, 2147483648), + (2, 1073741824), + (3, 3221225472), + (4, 536870912), + (5, 2684354560), + (6, 1610612736), + (7, 3758096384), + (8, 268435456), + (9, 2415919104), + (10, 1342177280), + (11, 3489660928), + (12, 805306368), + (13, 2952790016), + ], + ) + def test_reverse_bits(self, n: int, expected: int): + result = run_reverse_bits(Solution, n) + assert_reverse_bits(result, expected) diff --git a/leetcode_py/cli/resources/leetcode/json/problems/binary_tree_maximum_path_sum.json b/leetcode_py/cli/resources/leetcode/json/problems/binary_tree_maximum_path_sum.json new file mode 100644 index 0000000..e619e9f --- /dev/null +++ b/leetcode_py/cli/resources/leetcode/json/problems/binary_tree_maximum_path_sum.json @@ -0,0 +1,82 @@ +{ + "problem_name": "binary_tree_maximum_path_sum", + "solution_class_name": "Solution", + "problem_number": "124", + "problem_title": "Binary Tree Maximum Path Sum", + "difficulty": "Hard", + "topics": "Dynamic Programming, Tree, Depth-First Search, Binary Tree", + "_tags": { "list": ["blind-75"] }, + "readme_description": "A **path** in a binary tree is a sequence of nodes where each pair of adjacent nodes in the sequence has an edge connecting them. A node can only appear in the sequence **at most once**. Note that the path does not need to pass through the root.\n\nThe **path sum** of a path is the sum of the node's values in the path.\n\nGiven the `root` of a binary tree, return *the maximum **path sum** of any **non-empty** path*.", + "_readme_examples": { + "list": [ + { + "content": "![Example 1](https://assets.leetcode.com/uploads/2020/10/13/exx1.jpg)\n\n```\nInput: root = [1,2,3]\nOutput: 6\nExplanation: The optimal path is 2 -> 1 -> 3 with a path sum of 2 + 1 + 3 = 6.\n```" + }, + { + "content": "![Example 2](https://assets.leetcode.com/uploads/2020/10/13/exx2.jpg)\n\n```\nInput: root = [-10,9,20,null,null,15,7]\nOutput: 42\nExplanation: The optimal path is 15 -> 20 -> 7 with a path sum of 15 + 20 + 7 = 42.\n```" + } + ] + }, + "readme_constraints": "- The number of nodes in the tree is in the range [1, 3 * 10^4].\n- -1000 <= Node.val <= 1000", + "readme_additional": "", + "helpers_imports": "from leetcode_py import TreeNode", + "helpers_content": "", + "helpers_run_name": "max_path_sum", + "helpers_run_signature": "(solution_class: type, root_list: list[int | None])", + "helpers_run_body": " root = TreeNode[int].from_list(root_list)\n implementation = solution_class()\n return implementation.max_path_sum(root)", + "helpers_assert_name": "max_path_sum", + "helpers_assert_signature": "(result: int, expected: int) -> bool", + "helpers_assert_body": " assert result == expected\n return True", + "solution_imports": "from leetcode_py import TreeNode", + "solution_contents": "", + "solution_class_content": "", + "test_imports": "import pytest\nfrom leetcode_py import logged_test\nfrom .helpers import assert_max_path_sum, run_max_path_sum\nfrom .solution import Solution", + "test_content": "", + "test_class_name": "BinaryTreeMaximumPathSum", + "test_class_content": " def setup_method(self):\n self.solution = Solution()", + "_solution_methods": { + "list": [ + { + "name": "max_path_sum", + "signature": "(self, root: TreeNode[int] | None) -> int", + "body": " # TODO: Implement max_path_sum\n return 0" + } + ] + }, + "_test_helper_methods": { + "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }] + }, + "_test_methods": { + "list": [ + { + "name": "test_max_path_sum", + "signature": "(self, root_list: list[int | None], expected: int)", + "parametrize": "root_list, expected", + "test_cases": { + "list": [ + "([1, 2, 3], 6)", + "([-10, 9, 20, None, None, 15, 7], 42)", + "([1], 1)", + "([-3], -3)", + "([1, -2, 3], 4)", + "([5, 4, 8, 11, None, 13, 4, 7, 2, None, None, None, 1], 48)", + "([1, 2, 3, 4, 5], 11)", + "([-1, -2, -3], -1)", + "([1, -1, 2], 3)", + "([1, 2, -3, 4, 5], 11)", + "([1, 2, 3, None, None, 4, 5], 12)", + "([-1, 2, 3], 4)", + "([1, -2, -3, 1, 3, -2, None, -1], 3)", + "([2, -1], 2)", + "([1, 2], 3)" + ] + }, + "body": " result = run_max_path_sum(Solution, root_list)\n assert_max_path_sum(result, expected)" + } + ] + }, + "playground_imports": "from helpers import run_max_path_sum, assert_max_path_sum\nfrom solution import Solution\nfrom leetcode_py import TreeNode", + "playground_setup": "# Example test case\nroot_list: list[int | None] = [1, 2, 3]\nexpected: int = 6", + "playground_run": "result = run_max_path_sum(Solution, root_list)\nresult", + "playground_assert": "assert_max_path_sum(result, expected)" +} diff --git a/leetcode_py/cli/resources/leetcode/json/problems/find_minimum_in_rotated_sorted_array.json b/leetcode_py/cli/resources/leetcode/json/problems/find_minimum_in_rotated_sorted_array.json new file mode 100644 index 0000000..dea8d38 --- /dev/null +++ b/leetcode_py/cli/resources/leetcode/json/problems/find_minimum_in_rotated_sorted_array.json @@ -0,0 +1,85 @@ +{ + "problem_name": "find_minimum_in_rotated_sorted_array", + "solution_class_name": "Solution", + "problem_number": "153", + "problem_title": "Find Minimum in Rotated Sorted Array", + "difficulty": "Medium", + "topics": "Array, Binary Search", + "_tags": { "list": ["blind-75"] }, + "readme_description": "Suppose an array of length `n` sorted in ascending order is **rotated** between `1` and `n` times. For example, the array `nums = [0,1,2,4,5,6,7]` might become:\n\n- `[4,5,6,7,0,1,2]` if it was rotated `4` times.\n- `[0,1,2,4,5,6,7]` if it was rotated `7` times.\n\nNotice that **rotating** an array `[a[0], a[1], a[2], ..., a[n-1]]` 1 time results in the array `[a[n-1], a[0], a[1], a[2], ..., a[n-2]]`.\n\nGiven the sorted rotated array `nums` of **unique** elements, return *the minimum element of this array*.\n\nYou must write an algorithm that runs in O(log n) time.", + "_readme_examples": { + "list": [ + { + "content": "```\nInput: nums = [3,4,5,1,2]\nOutput: 1\nExplanation: The original array was [1,2,3,4,5] rotated 3 times.\n```" + }, + { + "content": "```\nInput: nums = [4,5,6,7,0,1,2]\nOutput: 0\nExplanation: The original array was [0,1,2,4,5,6,7] and it was rotated 4 times.\n```" + }, + { + "content": "```\nInput: nums = [11,13,15,17]\nOutput: 11\nExplanation: The original array was [11,13,15,17] and it was rotated 4 times.\n```" + } + ] + }, + "readme_constraints": "- n == nums.length\n- 1 <= n <= 5000\n- -5000 <= nums[i] <= 5000\n- All the integers of nums are **unique**.\n- nums is sorted and rotated between 1 and n times.", + "readme_additional": "", + "helpers_imports": "", + "helpers_content": "", + "helpers_run_name": "find_min", + "helpers_run_signature": "(solution_class: type, nums: list[int])", + "helpers_run_body": " implementation = solution_class()\n return implementation.find_min(nums)", + "helpers_assert_name": "find_min", + "helpers_assert_signature": "(result: int, expected: int) -> bool", + "helpers_assert_body": " assert result == expected\n return True", + "solution_imports": "", + "solution_contents": "", + "solution_class_content": "", + "test_imports": "import pytest\nfrom leetcode_py import logged_test\nfrom .helpers import assert_find_min, run_find_min\nfrom .solution import Solution", + "test_content": "", + "test_class_name": "FindMinimumInRotatedSortedArray", + "test_class_content": " def setup_method(self):\n self.solution = Solution()", + "_solution_methods": { + "list": [ + { + "name": "find_min", + "signature": "(self, nums: list[int]) -> int", + "body": " # TODO: Implement find_min\n return 0" + } + ] + }, + "_test_helper_methods": { + "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }] + }, + "_test_methods": { + "list": [ + { + "name": "test_find_min", + "signature": "(self, nums: list[int], expected: int)", + "parametrize": "nums, expected", + "test_cases": { + "list": [ + "([3, 4, 5, 1, 2], 1)", + "([4, 5, 6, 7, 0, 1, 2], 0)", + "([11, 13, 15, 17], 11)", + "([1], 1)", + "([2, 1], 1)", + "([1, 2, 3], 1)", + "([3, 1, 2], 1)", + "([2, 3, 1], 1)", + "([4, 5, 6, 7, 8, 1, 2, 3], 1)", + "([5, 6, 7, 8, 9, 10, 1, 2, 3, 4], 1)", + "([6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5], 1)", + "([7, 8, 9, 10, 11, 12, 13, 14, 1, 2, 3, 4, 5, 6], 1)", + "([8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7], 1)", + "([9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8], 1)", + "([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9], 1)" + ] + }, + "body": " result = run_find_min(Solution, nums)\n assert_find_min(result, expected)" + } + ] + }, + "playground_imports": "from helpers import run_find_min, assert_find_min\nfrom solution import Solution", + "playground_setup": "# Example test case\nnums: list[int] = [3, 4, 5, 1, 2]\nexpected: int = 1", + "playground_run": "result = run_find_min(Solution, nums)\nresult", + "playground_assert": "assert_find_min(result, expected)" +} diff --git a/leetcode_py/cli/resources/leetcode/json/problems/number_of_1_bits.json b/leetcode_py/cli/resources/leetcode/json/problems/number_of_1_bits.json new file mode 100644 index 0000000..42e2565 --- /dev/null +++ b/leetcode_py/cli/resources/leetcode/json/problems/number_of_1_bits.json @@ -0,0 +1,95 @@ +{ + "problem_name": "number_of_1_bits", + "solution_class_name": "Solution", + "problem_number": "191", + "problem_title": "Number of 1 Bits", + "difficulty": "Easy", + "topics": "Divide and Conquer, Bit Manipulation", + "_tags": { "list": ["blind-75"] }, + "readme_description": "Given a positive integer `n`, write a function that returns the number of set bits in its binary representation (also known as the Hamming weight).", + "_readme_examples": { + "list": [ + { + "content": "```\nInput: n = 11\nOutput: 3\nExplanation:\nThe input binary string 1011 has a total of three set bits.\n```" + }, + { + "content": "```\nInput: n = 128\nOutput: 1\nExplanation:\nThe input binary string 10000000 has a total of one set bit.\n```" + }, + { + "content": "```\nInput: n = 2147483645\nOutput: 30\nExplanation:\nThe input binary string 1111111111111111111111111111101 has a total of thirty set bits.\n```" + } + ] + }, + "constraints": { + "list": ["1 <= n <= 2^31 - 1"] + }, + "readme_constraints": "- 1 <= n <= 2^31 - 1", + "readme_additional": "", + "helpers_imports": "", + "helpers_content": "", + "helpers_run_name": "hamming_weight", + "helpers_run_signature": "(solution_class: type, n: int)", + "helpers_run_body": " implementation = solution_class()\n return implementation.hamming_weight(n)", + "helpers_assert_name": "hamming_weight", + "helpers_assert_signature": "(result: int, expected: int) -> bool", + "helpers_assert_body": " assert result == expected\n return True", + "solution_imports": "", + "solution_contents": "", + "solution_class_content": "", + "test_imports": "import pytest\nfrom leetcode_py import logged_test\nfrom .helpers import assert_hamming_weight, run_hamming_weight\nfrom .solution import Solution", + "test_content": "", + "test_class_name": "NumberOf1Bits", + "test_class_content": " def setup_method(self):\n self.solution = Solution()", + "_solution_methods": { + "list": [ + { + "name": "hamming_weight", + "signature": "(self, n: int) -> int", + "body": " # TODO: Implement hamming_weight\n return 0" + } + ] + }, + "_test_helper_methods": { + "list": [ + { + "name": "setup_method", + "parameters": "", + "body": "self.solution = Solution()" + } + ] + }, + "_test_methods": { + "list": [ + { + "name": "test_hamming_weight", + "signature": "(self, n: int, expected: int)", + "parametrize": "n, expected", + "test_cases": { + "list": [ + "(11, 3)", + "(128, 1)", + "(2147483645, 30)", + "(0, 0)", + "(1, 1)", + "(2, 1)", + "(3, 2)", + "(4, 1)", + "(5, 2)", + "(6, 2)", + "(7, 3)", + "(8, 1)", + "(15, 4)", + "(16, 1)", + "(255, 8)", + "(256, 1)" + ] + }, + "body": " result = run_hamming_weight(Solution, n)\n assert_hamming_weight(result, expected)" + } + ] + }, + "playground_imports": "from helpers import run_hamming_weight, assert_hamming_weight\nfrom solution import Solution", + "playground_setup": "# Example test case\nn = 11\nexpected = 3", + "playground_run": "result = run_hamming_weight(Solution, n)\nresult", + "playground_assert": "assert_hamming_weight(result, expected)" +} diff --git a/leetcode_py/cli/resources/leetcode/json/problems/reorder_list.json b/leetcode_py/cli/resources/leetcode/json/problems/reorder_list.json new file mode 100644 index 0000000..b05a227 --- /dev/null +++ b/leetcode_py/cli/resources/leetcode/json/problems/reorder_list.json @@ -0,0 +1,82 @@ +{ + "problem_name": "reorder_list", + "solution_class_name": "Solution", + "problem_number": "143", + "problem_title": "Reorder List", + "difficulty": "Medium", + "topics": "Linked List, Two Pointers, Stack, Recursion", + "_tags": { "list": ["blind-75"] }, + "readme_description": "You are given the head of a singly linked-list. The list can be represented as:\n\nL0 → L1 → … → Ln - 1 → Ln\n\n*Reorder the list to be on the following form:*\n\nL0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …\n\nYou may not modify the values in the list's nodes. Only nodes themselves may be changed.", + "_readme_examples": { + "list": [ + { + "content": "![Example 1](https://assets.leetcode.com/uploads/2021/03/04/reorder1linked-list.jpg)\n\n```\nInput: head = [1,2,3,4]\nOutput: [1,4,2,3]\n```" + }, + { + "content": "![Example 2](https://assets.leetcode.com/uploads/2021/03/09/reorder2-linked-list.jpg)\n\n```\nInput: head = [1,2,3,4,5]\nOutput: [1,5,2,4,3]\n```" + } + ] + }, + "readme_constraints": "- The number of nodes in the list is in the range [1, 5 * 10^4].\n- 1 <= Node.val <= 1000", + "readme_additional": "", + "helpers_imports": "from leetcode_py import ListNode", + "helpers_content": "", + "helpers_run_name": "reorder_list", + "helpers_run_signature": "(solution_class: type, head_list: list[int])", + "helpers_run_body": " head = ListNode[int].from_list(head_list)\n implementation = solution_class()\n implementation.reorder_list(head)\n return head.to_list() if head else []", + "helpers_assert_name": "reorder_list", + "helpers_assert_signature": "(result: list[int], expected: list[int]) -> bool", + "helpers_assert_body": " assert result == expected\n return True", + "solution_imports": "from leetcode_py import ListNode", + "solution_contents": "", + "solution_class_content": "", + "test_imports": "import pytest\nfrom leetcode_py import logged_test\nfrom .helpers import assert_reorder_list, run_reorder_list\nfrom .solution import Solution", + "test_content": "", + "test_class_name": "ReorderList", + "test_class_content": " def setup_method(self):\n self.solution = Solution()", + "_solution_methods": { + "list": [ + { + "name": "reorder_list", + "signature": "(self, head: ListNode[int] | None) -> None", + "body": " # TODO: Implement reorder_list\n pass" + } + ] + }, + "_test_helper_methods": { + "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }] + }, + "_test_methods": { + "list": [ + { + "name": "test_reorder_list", + "signature": "(self, head_list: list[int], expected: list[int])", + "parametrize": "head_list, expected", + "test_cases": { + "list": [ + "([1, 2, 3, 4], [1, 4, 2, 3])", + "([1, 2, 3, 4, 5], [1, 5, 2, 4, 3])", + "([1], [1])", + "([1, 2], [1, 2])", + "([1, 2, 3], [1, 3, 2])", + "([1, 2, 3, 4, 5, 6], [1, 6, 2, 5, 3, 4])", + "([1, 2, 3, 4, 5, 6, 7], [1, 7, 2, 6, 3, 5, 4])", + "([1, 2, 3, 4, 5, 6, 7, 8], [1, 8, 2, 7, 3, 6, 4, 5])", + "([1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 9, 2, 8, 3, 7, 4, 6, 5])", + "([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 10, 2, 9, 3, 8, 4, 7, 5, 6])", + "([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [1, 11, 2, 10, 3, 9, 4, 8, 5, 7, 6])", + "([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], [1, 12, 2, 11, 3, 10, 4, 9, 5, 8, 6, 7])", + "([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], [1, 13, 2, 12, 3, 11, 4, 10, 5, 9, 6, 8, 7])", + "([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], [1, 14, 2, 13, 3, 12, 4, 11, 5, 10, 6, 9, 7, 8])", + "([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [1, 15, 2, 14, 3, 13, 4, 12, 5, 11, 6, 10, 7, 9, 8])" + ] + }, + "body": " result = run_reorder_list(Solution, head_list)\n assert_reorder_list(result, expected)" + } + ] + }, + "playground_imports": "from helpers import run_reorder_list, assert_reorder_list\nfrom solution import Solution\nfrom leetcode_py import ListNode", + "playground_setup": "# Example test case\nhead_list: list[int] = [1, 2, 3, 4]\nexpected: list[int] = [1, 4, 2, 3]", + "playground_run": "result = run_reorder_list(Solution, head_list)\nresult", + "playground_assert": "assert_reorder_list(result, expected)" +} diff --git a/leetcode_py/cli/resources/leetcode/json/problems/reverse_bits.json b/leetcode_py/cli/resources/leetcode/json/problems/reverse_bits.json new file mode 100644 index 0000000..2cf01e0 --- /dev/null +++ b/leetcode_py/cli/resources/leetcode/json/problems/reverse_bits.json @@ -0,0 +1,83 @@ +{ + "problem_name": "reverse_bits", + "solution_class_name": "Solution", + "problem_number": "190", + "problem_title": "Reverse Bits", + "difficulty": "Easy", + "topics": "Divide and Conquer, Bit Manipulation", + "_tags": { "list": ["blind-75"] }, + "readme_description": "Reverse bits of a given 32 bits signed integer.", + "_readme_examples": { + "list": [ + { + "content": "```\nInput: n = 43261596\nOutput: 964176192\nExplanation:\n\n| Integer | Binary |\n|------------|-------------------------------------|\n| 43261596 | 00000010100101000001111010011100 |\n| 964176192 | 00111001011110000010100101000000 |\n```" + }, + { + "content": "```\nInput: n = 2147483644\nOutput: 1073741822\nExplanation:\n\n| Integer | Binary |\n|-------------|-------------------------------------|\n| 2147483644 | 01111111111111111111111111111100 |\n| 1073741822 | 00111111111111111111111111111110 |\n```" + } + ] + }, + "readme_constraints": "- 0 <= n <= 2^31 - 2\n- n is even.", + "readme_additional": "**Follow up:** If this function is called many times, how would you optimize it?", + "helpers_imports": "", + "helpers_content": "", + "helpers_run_name": "reverse_bits", + "helpers_run_signature": "(solution_class: type, n: int)", + "helpers_run_body": " implementation = solution_class()\n return implementation.reverse_bits(n)", + "helpers_assert_name": "reverse_bits", + "helpers_assert_signature": "(result: int, expected: int) -> bool", + "helpers_assert_body": " assert result == expected\n return True", + "solution_imports": "", + "solution_contents": "", + "solution_class_content": "", + "test_imports": "import pytest\nfrom leetcode_py import logged_test\nfrom .helpers import assert_reverse_bits, run_reverse_bits\nfrom .solution import Solution", + "test_content": "", + "test_class_name": "ReverseBits", + "test_class_content": " def setup_method(self):\n self.solution = Solution()", + "_solution_methods": { + "list": [ + { + "name": "reverse_bits", + "signature": "(self, n: int) -> int", + "body": " # TODO: Implement reverse_bits\n return 0" + } + ] + }, + "_test_helper_methods": { + "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }] + }, + "_test_methods": { + "list": [ + { + "name": "test_reverse_bits", + "signature": "(self, n: int, expected: int)", + "parametrize": "n, expected", + "test_cases": { + "list": [ + "(43261596, 964176192)", + "(2147483644, 1073741822)", + "(0, 0)", + "(1, 2147483648)", + "(2, 1073741824)", + "(3, 3221225472)", + "(4, 536870912)", + "(5, 2684354560)", + "(6, 1610612736)", + "(7, 3758096384)", + "(8, 268435456)", + "(9, 2415919104)", + "(10, 1342177280)", + "(11, 3489660928)", + "(12, 805306368)", + "(13, 2952790016)" + ] + }, + "body": " result = run_reverse_bits(Solution, n)\n assert_reverse_bits(result, expected)" + } + ] + }, + "playground_imports": "from helpers import run_reverse_bits, assert_reverse_bits\nfrom solution import Solution", + "playground_setup": "# Example test case\nn: int = 43261596\nexpected: int = 964176192", + "playground_run": "result = run_reverse_bits(Solution, n)\nresult", + "playground_assert": "assert_reverse_bits(result, expected)" +} diff --git a/leetcode_py/cli/resources/leetcode/json/tags.json5 b/leetcode_py/cli/resources/leetcode/json/tags.json5 index 44a8642..6acbb49 100644 --- a/leetcode_py/cli/resources/leetcode/json/tags.json5 +++ b/leetcode_py/cli/resources/leetcode/json/tags.json5 @@ -113,6 +113,7 @@ "alien_dictionary", "best_time_to_buy_and_sell_stock", "binary_tree_level_order_traversal", + "binary_tree_maximum_path_sum", "climbing_stairs", "clone_graph", "coin_change", @@ -124,6 +125,7 @@ "decode_ways", "design_add_and_search_words_data_structure", "find_median_from_data_stream", + "find_minimum_in_rotated_sorted_array", "group_anagrams", "house_robber", "implement_trie_prefix_tree", @@ -144,10 +146,13 @@ "merge_k_sorted_lists", "merge_two_sorted_lists", "minimum_window_substring", + "number_of_1_bits", "number_of_islands", "pacific_atlantic_water_flow", "product_of_array_except_self", "remove_nth_node_from_end_of_list", + "reorder_list", + "reverse_bits", "reverse_linked_list", "rotate_image", "same_tree", @@ -173,6 +178,7 @@ "best_time_to_buy_and_sell_stock", "binary_search", "binary_tree_level_order_traversal", + "binary_tree_maximum_path_sum", "binary_tree_right_side_view", "climbing_stairs", "clone_graph", @@ -189,6 +195,7 @@ "diameter_of_binary_tree", "evaluate_reverse_polish_notation", "find_median_from_data_stream", + "find_minimum_in_rotated_sorted_array", "find_the_duplicate_number", "gas_station", "group_anagrams", @@ -216,12 +223,15 @@ "merge_two_sorted_lists", "min_stack", "minimum_window_substring", + "number_of_1_bits", "number_of_islands", "pacific_atlantic_water_flow", "partition_equal_subset_sum", "permutations", "product_of_array_except_self", "remove_nth_node_from_end_of_list", + "reorder_list", + "reverse_bits", "reverse_linked_list", "rotate_image", "rotting_oranges", @@ -250,6 +260,7 @@ // Algo Master 75 - (on-going) "algo-master-75": [ "binary_tree_level_order_traversal", + "binary_tree_maximum_path_sum", "binary_tree_right_side_view", "clone_graph", "coin_change",