Skip to content

Commit 8246984

Browse files
committed
feat: add more problems
1 parent 00c39ff commit 8246984

File tree

21 files changed

+884
-7
lines changed

21 files changed

+884
-7
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"problem_name": "binary_search",
3+
"solution_class_name": "Solution",
4+
"problem_number": "704",
5+
"problem_title": "Binary Search",
6+
"difficulty": "Easy",
7+
"topics": "Array, Binary Search",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given an array of integers `nums` which is sorted in ascending order, and an integer `target`, write a function to search `target` in `nums`. If `target` exists, then return its index. Otherwise, return `-1`.\n\nYou must write an algorithm with `O(log n)` runtime complexity.",
10+
"readme_examples": [
11+
{
12+
"content": "```\nInput: nums = [-1,0,3,5,9,12], target = 9\nOutput: 4\n```\n**Explanation:** 9 exists in nums and its index is 4"
13+
},
14+
{
15+
"content": "```\nInput: nums = [-1,0,3,5,9,12], target = 2\nOutput: -1\n```\n**Explanation:** 2 does not exist in nums so return -1"
16+
}
17+
],
18+
"readme_constraints": "- `1 <= nums.length <= 10^4`\n- `-10^4 < nums[i], target < 10^4`\n- All the integers in `nums` are **unique**.\n- `nums` is sorted in ascending order.",
19+
"readme_additional": "",
20+
"solution_imports": "",
21+
"solution_methods": [
22+
{
23+
"name": "search",
24+
"parameters": "nums: list[int], target: int",
25+
"return_type": "int",
26+
"dummy_return": "-1"
27+
}
28+
],
29+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
30+
"test_class_name": "BinarySearch",
31+
"test_helper_methods": [
32+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
33+
],
34+
"test_methods": [
35+
{
36+
"name": "test_search",
37+
"parametrize": "nums, target, expected",
38+
"parametrize_typed": "nums: list[int], target: int, expected: int",
39+
"test_cases": "[([\u22121, 0, 3, 5, 9, 12], 9, 4), ([\u22121, 0, 3, 5, 9, 12], 2, \u22121), ([5], 5, 0), ([5], \u22125, \u22121), ([1, 3, 5, 7, 9], 1, 0), ([1, 3, 5, 7, 9], 9, 4), ([1, 3, 5, 7, 9], 4, \u22121)]",
40+
"body": "result = self.solution.search(nums, target)\nassert result == expected"
41+
}
42+
],
43+
"playground_imports": "from solution import Solution",
44+
"playground_test_case": "# Example test case\nnums = [-1, 0, 3, 5, 9, 12]\ntarget = 9\nexpected = 4",
45+
"playground_execution": "result = Solution().search(nums, target)\nresult",
46+
"playground_assertion": "assert result == expected"
47+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"problem_name": "linked_list_cycle",
3+
"solution_class_name": "Solution",
4+
"problem_number": "141",
5+
"problem_title": "Linked List Cycle",
6+
"difficulty": "Easy",
7+
"topics": "Hash Table, Linked List, Two Pointers",
8+
"tags": [],
9+
"readme_description": "Given `head`, the head of a linked list, determine if the linked list has a cycle in it.\n\nThere is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the `next` pointer. Internally, `pos` is used to denote the index of the node that tail's `next` pointer is connected to. **Note that `pos` is not passed as a parameter**.\n\nReturn `true` *if there is a cycle in the linked list*. Otherwise, return `false`.",
10+
"readme_examples": [
11+
{
12+
"content": "![Example 1](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist.png)\n\n```\nInput: head = [3,2,0,-4], pos = 1\nOutput: true\n```\n**Explanation:** There is a cycle in the linked list, where the tail connects to the 1st node (0-indexed)."
13+
},
14+
{
15+
"content": "![Example 2](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist_test2.png)\n\n```\nInput: head = [1,2], pos = 0\nOutput: true\n```\n**Explanation:** There is a cycle in the linked list, where the tail connects to the 0th node."
16+
},
17+
{
18+
"content": "![Example 3](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist_test3.png)\n\n```\nInput: head = [1], pos = -1\nOutput: false\n```\n**Explanation:** There is no cycle in the linked list."
19+
}
20+
],
21+
"readme_constraints": "- The number of the nodes in the list is in the range `[0, 10^4]`.\n- `-10^5 <= Node.val <= 10^5`\n- `pos` is `-1` or a **valid index** in the linked-list.",
22+
"readme_additional": "**Follow up:** Can you solve it using `O(1)` (i.e. constant) memory?",
23+
"solution_imports": "from leetcode_py import ListNode",
24+
"solution_methods": [
25+
{
26+
"name": "has_cycle",
27+
"parameters": "head: ListNode[int] | None",
28+
"return_type": "bool",
29+
"dummy_return": "False"
30+
}
31+
],
32+
"test_imports": "import pytest\nfrom leetcode_py import ListNode\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
33+
"test_class_name": "LinkedListCycle",
34+
"test_helper_methods": [
35+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" },
36+
{
37+
"name": "_create_cycle_list",
38+
"parameters": "values: list[int], pos: int",
39+
"body": "if not values:\n return None\n\nhead = ListNode.from_list(values)\nif pos == -1:\n return head\n\n# Find the node at position pos\ncurrent = head\nfor _ in range(pos):\n current = current.next\ncycle_node = current\n\n# Find the tail\ntail = head\nwhile tail.next:\n tail = tail.next\n\n# Create cycle\ntail.next = cycle_node\nreturn head"
40+
}
41+
],
42+
"test_methods": [
43+
{
44+
"name": "test_has_cycle",
45+
"parametrize": "values, pos, expected",
46+
"parametrize_typed": "values: list[int], pos: int, expected: bool",
47+
"test_cases": "[([3, 2, 0, -4], 1, True), ([1, 2], 0, True), ([1], -1, False), ([], -1, False), ([1, 2, 3, 4, 5], 2, True), ([1, 2, 3], -1, False)]",
48+
"body": "head = self._create_cycle_list(values, pos)\nresult = self.solution.has_cycle(head)\nassert result == expected"
49+
}
50+
],
51+
"playground_imports": "from leetcode_py import ListNode\nfrom solution import Solution",
52+
"playground_test_case": "# Example test case\nvalues = [3, 2, 0, -4]\npos = 1\nexpected = True",
53+
"playground_execution": "head = create_cycle_list(values, pos)\nresult = Solution().has_cycle(head)\nresult",
54+
"playground_assertion": "assert result == expected"
55+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"problem_name": "lowest_common_ancestor_of_a_binary_search_tree",
3+
"solution_class_name": "Solution",
4+
"problem_number": "235",
5+
"problem_title": "Lowest Common Ancestor of a Binary Search Tree",
6+
"difficulty": "Medium",
7+
"topics": "Tree, Depth-First Search, Binary Search Tree, Binary Tree",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given a binary search tree (BST), find the lowest common ancestor (LCA) node of two given nodes in the BST.\n\nAccording to the definition of LCA on Wikipedia: \"The lowest common ancestor is defined between two nodes `p` and `q` as the lowest node in `T` that has both `p` and `q` as descendants (where we allow **a node to be a descendant of itself**).\"",
10+
"readme_examples": [
11+
{
12+
"content": "![Example 1](https://assets.leetcode.com/uploads/2018/12/14/binarysearchtree_improved.png)\n\n```\nInput: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8\nOutput: 6\n```\n**Explanation:** The LCA of nodes 2 and 8 is 6."
13+
},
14+
{
15+
"content": "![Example 2](https://assets.leetcode.com/uploads/2018/12/14/binarysearchtree_improved.png)\n\n```\nInput: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4\nOutput: 2\n```\n**Explanation:** The LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition."
16+
},
17+
{ "content": "```\nInput: root = [2,1], p = 2, q = 1\nOutput: 2\n```" }
18+
],
19+
"readme_constraints": "- The number of nodes in the tree is in the range `[2, 10^5]`.\n- `-10^9 <= Node.val <= 10^9`\n- All `Node.val` are **unique**.\n- `p != q`\n- `p` and `q` will exist in the BST.",
20+
"readme_additional": "",
21+
"solution_imports": "from leetcode_py import TreeNode",
22+
"solution_methods": [
23+
{
24+
"name": "lowest_common_ancestor",
25+
"parameters": "root: TreeNode[int] | None, p: TreeNode[int], q: TreeNode[int]",
26+
"return_type": "TreeNode[int] | None",
27+
"dummy_return": "None"
28+
}
29+
],
30+
"test_imports": "import pytest\nfrom leetcode_py import TreeNode\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
31+
"test_class_name": "LowestCommonAncestorOfABinarySearchTree",
32+
"test_helper_methods": [
33+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" },
34+
{
35+
"name": "_find_node",
36+
"parameters": "root: TreeNode[int], val: int",
37+
"body": "if not root:\n return None\nif root.val == val:\n return root\nleft = self._find_node(root.left, val)\nif left:\n return left\nreturn self._find_node(root.right, val)"
38+
}
39+
],
40+
"test_methods": [
41+
{
42+
"name": "test_lowest_common_ancestor",
43+
"parametrize": "root_list, p_val, q_val, expected_val",
44+
"parametrize_typed": "root_list: list[int | None], p_val: int, q_val: int, expected_val: int",
45+
"test_cases": "[([6, 2, 8, 0, 4, 7, 9, None, None, 3, 5], 2, 8, 6), ([6, 2, 8, 0, 4, 7, 9, None, None, 3, 5], 2, 4, 2), ([2, 1], 2, 1, 2), ([2, 1], 1, 2, 2), ([6, 2, 8, 0, 4, 7, 9], 0, 4, 2), ([6, 2, 8, 0, 4, 7, 9], 7, 9, 8)]",
46+
"body": "root = TreeNode[int].from_list(root_list)\nassert root is not None\np = self._find_node(root, p_val)\nq = self._find_node(root, q_val)\nassert p is not None and q is not None\nresult = self.solution.lowest_common_ancestor(root, p, q)\nassert result is not None\nassert result.val == expected_val"
47+
}
48+
],
49+
"playground_imports": "from leetcode_py import TreeNode\nfrom solution import Solution",
50+
"playground_test_case": "# Example test case\nroot_list = [6, 2, 8, 0, 4, 7, 9, None, None, 3, 5]\np_val = 2\nq_val = 8\nexpected_val = 6",
51+
"playground_execution": "root = TreeNode[int].from_list(root_list)\np = find_node(root, p_val)\nq = find_node(root, q_val)\nresult = Solution().lowest_common_ancestor(root, p, q)\nresult.val if result else None",
52+
"playground_assertion": "assert result and result.val == expected_val"
53+
}

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
PYTHON_VERSION = 3.13
2-
PROBLEM ?= search_in_rotated_sorted_array
2+
PROBLEM ?= linked_list_cycle
33
FORCE ?= 0
44

55
sync_submodules:

leetcode/binary_search/README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Binary Search
2+
3+
**Difficulty:** Easy
4+
**Topics:** Array, Binary Search
5+
**Tags:** grind-75
6+
7+
**LeetCode:** [Problem 704](https://leetcode.com/problems/binary-search/description/)
8+
9+
## Problem Description
10+
11+
Given an array of integers `nums` which is sorted in ascending order, and an integer `target`, write a function to search `target` in `nums`. If `target` exists, then return its index. Otherwise, return `-1`.
12+
13+
You must write an algorithm with `O(log n)` runtime complexity.
14+
15+
## Examples
16+
17+
### Example 1:
18+
19+
```
20+
Input: nums = [-1,0,3,5,9,12], target = 9
21+
Output: 4
22+
```
23+
24+
**Explanation:** 9 exists in nums and its index is 4
25+
26+
### Example 2:
27+
28+
```
29+
Input: nums = [-1,0,3,5,9,12], target = 2
30+
Output: -1
31+
```
32+
33+
**Explanation:** 2 does not exist in nums so return -1
34+
35+
## Constraints
36+
37+
- `1 <= nums.length <= 10^4`
38+
- `-10^4 < nums[i], target < 10^4`
39+
- All the integers in `nums` are **unique**.
40+
- `nums` is sorted in ascending order.

leetcode/binary_search/__init__.py

Whitespace-only changes.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"id": "imports",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"from solution import Solution"
11+
]
12+
},
13+
{
14+
"cell_type": "code",
15+
"execution_count": null,
16+
"id": "setup",
17+
"metadata": {},
18+
"outputs": [],
19+
"source": [
20+
"# Example test case\n",
21+
"nums = [-1, 0, 3, 5, 9, 12]\n",
22+
"target = 9\n",
23+
"expected = 4"
24+
]
25+
},
26+
{
27+
"cell_type": "code",
28+
"execution_count": null,
29+
"id": "execute",
30+
"metadata": {},
31+
"outputs": [],
32+
"source": [
33+
"result = Solution().search(nums, target)\n",
34+
"result"
35+
]
36+
},
37+
{
38+
"cell_type": "code",
39+
"execution_count": null,
40+
"id": "test",
41+
"metadata": {},
42+
"outputs": [],
43+
"source": [
44+
"assert result == expected"
45+
]
46+
}
47+
],
48+
"metadata": {
49+
"kernelspec": {
50+
"display_name": "leetcode-py-py3.13",
51+
"language": "python",
52+
"name": "python3"
53+
},
54+
"language_info": {
55+
"codemirror_mode": {
56+
"name": "ipython",
57+
"version": 3
58+
},
59+
"file_extension": ".py",
60+
"mimetype": "text/x-python",
61+
"name": "python",
62+
"nbconvert_exporter": "python3",
63+
"pygments_lexer": "ipython3",
64+
"version": "3.13.7"
65+
}
66+
},
67+
"nbformat": 4,
68+
"nbformat_minor": 5
69+
}

leetcode/binary_search/solution.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Solution:
2+
# Time: O(log n)
3+
# Space: O(1)
4+
def search(self, nums: list[int], target: int) -> int:
5+
left, right = 0, len(nums) - 1
6+
7+
while left <= right:
8+
mid = (left + right) // 2
9+
10+
if nums[mid] == target:
11+
return mid
12+
elif nums[mid] < target:
13+
left = mid + 1
14+
else:
15+
right = mid - 1
16+
17+
return -1

leetcode/binary_search/tests.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import pytest
2+
3+
from leetcode_py.test_utils import logged_test
4+
5+
from .solution import Solution
6+
7+
8+
class TestBinarySearch:
9+
def setup_method(self):
10+
self.solution = Solution()
11+
12+
@pytest.mark.parametrize(
13+
"nums, target, expected",
14+
[
15+
# Original examples
16+
([-1, 0, 3, 5, 9, 12], 9, 4),
17+
([-1, 0, 3, 5, 9, 12], 2, -1),
18+
# Single element
19+
([5], 5, 0),
20+
([5], -5, -1),
21+
# Target at boundaries
22+
([1, 3, 5, 7, 9], 1, 0),
23+
([1, 3, 5, 7, 9], 9, 4),
24+
# Target not found
25+
([1, 3, 5, 7, 9], 4, -1),
26+
# Two elements
27+
([1, 3], 1, 0),
28+
([1, 3], 3, 1),
29+
([1, 3], 2, -1),
30+
# Negative numbers
31+
([-5, -2, 0, 3, 7], -2, 1),
32+
([-5, -2, 0, 3, 7], 0, 2),
33+
([-5, -2, 0, 3, 7], -1, -1),
34+
],
35+
)
36+
@logged_test
37+
def test_search(self, nums: list[int], target: int, expected: int):
38+
result = self.solution.search(nums, target)
39+
assert result == expected
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Linked List Cycle
2+
3+
**Difficulty:** Easy
4+
**Topics:** Hash Table, Linked List, Two Pointers
5+
**Tags:**
6+
7+
**LeetCode:** [Problem 141](https://leetcode.com/problems/linked-list-cycle/description/)
8+
9+
## Problem Description
10+
11+
Given `head`, the head of a linked list, determine if the linked list has a cycle in it.
12+
13+
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the `next` pointer. Internally, `pos` is used to denote the index of the node that tail's `next` pointer is connected to. **Note that `pos` is not passed as a parameter**.
14+
15+
Return `true` _if there is a cycle in the linked list_. Otherwise, return `false`.
16+
17+
## Examples
18+
19+
### Example 1:
20+
21+
![Example 1](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist.png)
22+
23+
```
24+
Input: head = [3,2,0,-4], pos = 1
25+
Output: true
26+
```
27+
28+
**Explanation:** There is a cycle in the linked list, where the tail connects to the 1st node (0-indexed).
29+
30+
### Example 2:
31+
32+
![Example 2](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist_test2.png)
33+
34+
```
35+
Input: head = [1,2], pos = 0
36+
Output: true
37+
```
38+
39+
**Explanation:** There is a cycle in the linked list, where the tail connects to the 0th node.
40+
41+
### Example 3:
42+
43+
![Example 3](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist_test3.png)
44+
45+
```
46+
Input: head = [1], pos = -1
47+
Output: false
48+
```
49+
50+
**Explanation:** There is no cycle in the linked list.
51+
52+
## Constraints
53+
54+
- The number of the nodes in the list is in the range `[0, 10^4]`.
55+
- `-10^5 <= Node.val <= 10^5`
56+
- `pos` is `-1` or a **valid index** in the linked-list.
57+
58+
**Follow up:** Can you solve it using `O(1)` (i.e. constant) memory?

0 commit comments

Comments
 (0)