Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .templates/leetcode/examples/linked_list.json5
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
solution_methods: [
{
name: "reverse_between", // snake_case method name
parameters: "head: ListNode | None, left: int, right: int", // Use ListNode | None for nullable parameters
return_type: "ListNode | None", // Modern union syntax
parameters: "head: ListNode[int] | None, left: int, right: int", // Use ListNode[int] | None for nullable parameters
return_type: "ListNode[int] | None", // Modern union syntax with explicit generic type
dummy_return: "None", // None for linked list problems
},
],
Expand All @@ -65,14 +65,14 @@
parametrize_typed: "head_list: list[int], left: int, right: int, expected_list: list[int]",
test_cases: "[([1, 2, 3, 4, 5], 2, 4, [1, 4, 3, 2, 5]), ([5], 1, 1, [5])]",
// IMPORTANT: Linked list test body converts arrays to ListNode and compares objects directly
body: "head = ListNode.from_list(head_list)\nexpected = ListNode.from_list(expected_list)\nresult = self.solution.reverse_between(head, left, right)\nassert result == expected",
body: "head = ListNode[int].from_list(head_list)\nexpected = ListNode[int].from_list(expected_list)\nresult = self.solution.reverse_between(head, left, right)\nassert result == expected",
},
],

// === PLAYGROUND NOTEBOOK ===
// IMPORTANT: Linked list playground needs ListNode import and conversion
playground_imports: "from solution import Solution\n\nfrom leetcode_py import ListNode",
playground_test_case: "# Example test case\nhead_list = [1, 2, 3, 4, 5]\nhead = ListNode.from_list(head_list)\nleft, right = 2, 4\nexpected = ListNode.from_list([1, 4, 3, 2, 5])",
playground_test_case: "# Example test case\nhead_list = [1, 2, 3, 4, 5]\nhead = ListNode[int].from_list(head_list)\nleft, right = 2, 4\nexpected = ListNode[int].from_list([1, 4, 3, 2, 5])",
playground_execution: "result = Solution().reverse_between(head, left, right)\nresult",
playground_assertion: "assert result == expected",
}
8 changes: 4 additions & 4 deletions .templates/leetcode/examples/tree.json5
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
solution_methods: [
{
name: "invert_tree", // snake_case method name
parameters: "root: TreeNode | None", // Use TreeNode | None for nullable tree parameters
return_type: "TreeNode | None", // Modern union syntax (not Optional[TreeNode])
parameters: "root: TreeNode[int] | None", // Use TreeNode[int] | None for nullable tree parameters
return_type: "TreeNode[int] | None", // Modern union syntax with explicit generic type
dummy_return: "None", // None for tree problems
},
],
Expand All @@ -69,14 +69,14 @@
parametrize_typed: "root_list: list[int | None], expected_list: list[int | None]",
test_cases: "[([4, 2, 7, 1, 3, 6, 9], [4, 7, 2, 9, 6, 3, 1]), ([2, 1, 3], [2, 3, 1]), ([], [])]",
// IMPORTANT: Tree test body converts arrays to TreeNode and compares objects directly
body: "root = TreeNode.from_list(root_list)\nexpected = TreeNode.from_list(expected_list)\nresult = self.solution.invert_tree(root)\nassert result == expected",
body: "root = TreeNode[int].from_list(root_list)\nexpected = TreeNode[int].from_list(expected_list)\nresult = self.solution.invert_tree(root)\nassert result == expected",
},
],

// === PLAYGROUND NOTEBOOK ===
// IMPORTANT: Tree playground needs TreeNode import and conversion
playground_imports: "from solution import Solution\n\nfrom leetcode_py import TreeNode",
playground_test_case: "# Example test case\nroot_list: list[int | None] = [4, 2, 7, 1, 3, 6, 9]\nroot = TreeNode.from_list(root_list)\nexpected = TreeNode.from_list([4, 7, 2, 9, 6, 3, 1])",
playground_test_case: "# Example test case\nroot_list: list[int | None] = [4, 2, 7, 1, 3, 6, 9]\nroot = TreeNode[int].from_list(root_list)\nexpected = TreeNode[int].from_list([4, 7, 2, 9, 6, 3, 1])",
playground_execution: "result = Solution().invert_tree(root)\nresult",
playground_assertion: "assert result == expected",
}
8 changes: 4 additions & 4 deletions .templates/leetcode/json/invert_binary_tree.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
"solution_methods": [
{
"name": "invert_tree",
"parameters": "root: TreeNode | None",
"return_type": "TreeNode | None",
"parameters": "root: TreeNode[int] | None",
"return_type": "TreeNode[int] | None",
"dummy_return": "None"
}
],
Expand All @@ -34,11 +34,11 @@
"parametrize": "root_list, expected_list",
"parametrize_typed": "root_list: list[int | None], expected_list: list[int | None]",
"test_cases": "[([4, 2, 7, 1, 3, 6, 9], [4, 7, 2, 9, 6, 3, 1]), ([2, 1, 3], [2, 3, 1]), ([], [])]",
"body": "root = TreeNode.from_list(root_list)\nexpected = TreeNode.from_list(expected_list)\nresult = self.solution.invert_tree(root)\nassert result == expected"
"body": "root = TreeNode[int].from_list(root_list)\nexpected = TreeNode[int].from_list(expected_list)\nresult = self.solution.invert_tree(root)\nassert result == expected"
}
],
"playground_imports": "from solution import Solution\n\nfrom leetcode_py import TreeNode",
"playground_test_case": "# Example test case\nroot_list: list[int | None] = [4, 2, 7, 1, 3, 6, 9]\nroot = TreeNode.from_list(root_list)\nexpected = TreeNode.from_list([4, 7, 2, 9, 6, 3, 1])",
"playground_test_case": "# Example test case\nroot_list: list[int | None] = [4, 2, 7, 1, 3, 6, 9]\nroot = TreeNode[int].from_list(root_list)\nexpected = TreeNode[int].from_list([4, 7, 2, 9, 6, 3, 1])",
"playground_execution": "result = Solution().invert_tree(root)\nresult",
"playground_assertion": "assert result == expected"
}
8 changes: 4 additions & 4 deletions .templates/leetcode/json/reverse_linked_list_ii.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"solution_methods": [
{
"name": "reverse_between",
"parameters": "head: ListNode | None, left: int, right: int",
"return_type": "ListNode | None",
"parameters": "head: ListNode[int] | None, left: int, right: int",
"return_type": "ListNode[int] | None",
"dummy_return": "None"
}
],
Expand All @@ -33,11 +33,11 @@
"parametrize": "head_list, left, right, expected_list",
"parametrize_typed": "head_list: list[int], left: int, right: int, expected_list: list[int]",
"test_cases": "[([1, 2, 3, 4, 5], 2, 4, [1, 4, 3, 2, 5]), ([5], 1, 1, [5])]",
"body": "head = ListNode.from_list(head_list)\nexpected = ListNode.from_list(expected_list)\nresult = self.solution.reverse_between(head, left, right)\nassert result == expected"
"body": "head = ListNode[int].from_list(head_list)\nexpected = ListNode[int].from_list(expected_list)\nresult = self.solution.reverse_between(head, left, right)\nassert result == expected"
}
],
"playground_imports": "from solution import Solution\n\nfrom leetcode_py import ListNode",
"playground_test_case": "# Example test case\nhead_list = [1, 2, 3, 4, 5]\nhead = ListNode.from_list(head_list)\nleft, right = 2, 4\nexpected = ListNode.from_list([1, 4, 3, 2, 5])",
"playground_test_case": "# Example test case\nhead_list = [1, 2, 3, 4, 5]\nhead = ListNode[int].from_list(head_list)\nleft, right = 2, 4\nexpected = ListNode[int].from_list([1, 4, 3, 2, 5])",
"playground_execution": "result = Solution().reverse_between(head, left, right)\nresult",
"playground_assertion": "assert result == expected"
}
2 changes: 1 addition & 1 deletion leetcode/invert_binary_tree/playground.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"id": "setup",
"metadata": {},
"outputs": [],
"source": ["# Example test case\nroot_list: list[int | None] = [4, 2, 7, 1, 3, 6, 9]\nroot = TreeNode.from_list(root_list)\nexpected = TreeNode.from_list([4, 7, 2, 9, 6, 3, 1])"]
"source": ["# Example test case\nroot_list: list[int | None] = [4, 2, 7, 1, 3, 6, 9]\nroot = TreeNode[int].from_list(root_list)\nexpected = TreeNode[int].from_list([4, 7, 2, 9, 6, 3, 1])"]
},
{
"cell_type": "code",
Expand Down
10 changes: 5 additions & 5 deletions leetcode/invert_binary_tree/solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Solution:
# DFS recursive
# Time: O(n)
# Space: O(h) where h is height of tree
def invert_tree(self, root: TreeNode | None) -> TreeNode | None:
def invert_tree(self, root: TreeNode[int] | None) -> TreeNode[int] | None:
if not root:
return None

Expand All @@ -22,11 +22,11 @@ class SolutionDFS:
# DFS iterative
# Time: O(n)
# Space: O(h) where h is height of tree
def invert_tree(self, root: TreeNode | None) -> TreeNode | None:
def invert_tree(self, root: TreeNode[int] | None) -> TreeNode[int] | None:
if not root:
return None

stack: list[TreeNode | None] = [root]
stack: list[TreeNode[int] | None] = [root]
while stack:
node = stack.pop()
if node is None:
Expand All @@ -42,11 +42,11 @@ def invert_tree(self, root: TreeNode | None) -> TreeNode | None:
class SolutionBFS:
# Time: O(n)
# Space: O(w) where w is maximum width of tree
def invert_tree(self, root: TreeNode | None) -> TreeNode | None:
def invert_tree(self, root: TreeNode[int] | None) -> TreeNode[int] | None:
if not root:
return None

queue: deque[TreeNode | None] = deque([root])
queue: deque[TreeNode[int] | None] = deque([root])
while queue:
node = queue.popleft()
if node is None:
Expand Down
4 changes: 2 additions & 2 deletions leetcode/invert_binary_tree/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_invert_tree(
solution_class: type[Solution | SolutionDFS | SolutionBFS],
):
solution = solution_class()
root = TreeNode.from_list(root_list)
expected = TreeNode.from_list(expected_list)
root = TreeNode[int].from_list(root_list)
expected = TreeNode[int].from_list(expected_list)
result = solution.invert_tree(root)
assert result == expected
2 changes: 1 addition & 1 deletion leetcode/lru_cache/solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

class LRUCache:
# Space: O(capacity)
def __init__(self, capacity: int):
def __init__(self, capacity: int) -> None:
self.capacity = capacity
self.cache: OrderedDict[int, int] = OrderedDict()

Expand Down
2 changes: 1 addition & 1 deletion leetcode/reverse_linked_list_ii/playground.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"id": "setup",
"metadata": {},
"outputs": [],
"source": ["# Example test case\nhead_list = [1, 2, 3, 4, 5]\nhead = ListNode.from_list(head_list)\nleft, right = 2, 4\nexpected = ListNode.from_list([1, 4, 3, 2, 5])"]
"source": ["# Example test case\nhead_list = [1, 2, 3, 4, 5]\nhead = ListNode[int].from_list(head_list)\nleft, right = 2, 4\nexpected = ListNode[int].from_list([1, 4, 3, 2, 5])"]
},
{
"cell_type": "code",
Expand Down
4 changes: 2 additions & 2 deletions leetcode/reverse_linked_list_ii/solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
class Solution:
# Time: O(n)
# Space: O(1)
def reverse_between(self, head: ListNode | None, left: int, right: int) -> ListNode | None:
def reverse_between(self, head: ListNode[int] | None, left: int, right: int) -> ListNode[int] | None:
if not head or left == right:
return head

dummy = ListNode(0)
dummy = ListNode[int](0)
dummy.next = head
prev = dummy

Expand Down
4 changes: 2 additions & 2 deletions leetcode/reverse_linked_list_ii/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def setup_method(self):
def test_reverse_between(
self, head_list: list[int], left: int, right: int, expected_list: list[int]
):
head = ListNode.from_list(head_list)
expected = ListNode.from_list(expected_list)
head = ListNode[int].from_list(head_list)
expected = ListNode[int].from_list(expected_list)
result = self.solution.reverse_between(head, left, right)
assert result == expected
16 changes: 11 additions & 5 deletions leetcode_py/data_structures/list_node.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
class ListNode:
def __init__(self, val: int = 0, next: "ListNode | None" = None):
from typing import Generic, TypeVar

# TODO: Remove TypeVar when minimum Python version is 3.12+ (use class ListNode[T]: syntax)
T = TypeVar("T")


class ListNode(Generic[T]):
def __init__(self, val: T, next: "ListNode[T] | None" = None):
self.val = val
self.next = next

@classmethod
def from_list(cls, arr: list[int]) -> "ListNode | None":
def from_list(cls, arr: list[T]) -> "ListNode[T] | None":
if not arr:
return None
head = cls(arr[0])
Expand All @@ -14,9 +20,9 @@ def from_list(cls, arr: list[int]) -> "ListNode | None":
current = current.next
return head

def to_list(self) -> list[int]:
def to_list(self) -> list[T]:
result = []
current: "ListNode | None" = self
current: "ListNode[T] | None" = self
while current:
result.append(current.val)
current = current.next
Expand Down
21 changes: 13 additions & 8 deletions leetcode_py/data_structures/tree_node.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
from typing import Any, Generic, TypeVar

import graphviz
from anytree import Node, RenderTree

# TODO: Remove TypeVar when minimum Python version is 3.12+ (use class TreeNode[T]: syntax)
T = TypeVar("T")


def build_anytree(node: "TreeNode | None", parent: Node | None = None) -> Node | None:
def build_anytree(node: "TreeNode[Any] | None", parent: Node | None = None) -> Node | None:
if not node:
return Node("None", parent=parent) if parent else None
current = Node(str(node.val), parent=parent)
Expand All @@ -12,7 +17,7 @@ def build_anytree(node: "TreeNode | None", parent: Node | None = None) -> Node |
return current


def add_nodes(dot: graphviz.Digraph, node: "TreeNode | None", node_id: int = 0) -> int:
def add_nodes(dot: graphviz.Digraph, node: "TreeNode[Any] | None", node_id: int = 0) -> int:
if not node:
return node_id

Expand All @@ -31,14 +36,14 @@ def add_nodes(dot: graphviz.Digraph, node: "TreeNode | None", node_id: int = 0)
return next_id - 1


class TreeNode:
def __init__(self, val: int = 0, left: "TreeNode | None" = None, right: "TreeNode | None" = None):
class TreeNode(Generic[T]):
def __init__(self, val: T, left: "TreeNode[T] | None" = None, right: "TreeNode[T] | None" = None):
self.val = val
self.left = left
self.right = right

@classmethod
def from_list(cls, arr: list[int | None]) -> "TreeNode | None":
def from_list(cls, arr: list[T | None]) -> "TreeNode[T] | None":
"""Convert array representation to binary tree."""
if not arr or arr[0] is None:
return None
Expand Down Expand Up @@ -66,10 +71,10 @@ def from_list(cls, arr: list[int | None]) -> "TreeNode | None":

return root

def to_list(self) -> list[int | None]:
def to_list(self) -> list[T | None]:
"""Convert binary tree to array representation."""
result: list[int | None] = []
queue: list[TreeNode | None] = [self]
result: list[T | None] = []
queue: list[TreeNode[T] | None] = [self]

while queue:
node = queue.pop(0)
Expand Down
Loading
Loading