-
Notifications
You must be signed in to change notification settings - Fork 1
Add solutions and explanations for problems 2211, 190, 191, 201, 202, 207, 209, 210, 211, 212, 221, 222, 224, 226, 295 #97
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
Conversation
… 207, 209, 210, 211, 212, 221, 222, 224, 226, 295
Reviewer's GuideAdds accepted Python solutions and detailed English explanations for 15 LeetCode problems across bit manipulation, trees, graphs, DP, and data structures, and modernizes the existing invert-binary-tree solution to LeetCode’s class-based interface. Class diagram for trie-based word search and dictionary solutionsclassDiagram
class TrieNode {
dict children
bool is_end
str word
__init__()
}
class WordDictionary {
TrieNode root
__init__()
addWord(word: str) void
search(word: str) bool
}
class SolutionWordSearchII {
findWords(board: List_List_str, words: List_str) List_str
dfs(row: int, col: int, node: TrieNode) void
}
WordDictionary --> TrieNode : uses
SolutionWordSearchII --> TrieNode : builds_trie_from_words
%% Representing the LeetCode class name for problem 212
class SolutionWordSearchII as Solution_212
Class diagram for MedianFinder data stream structureclassDiagram
class MedianFinder {
list max_heap
list min_heap
__init__()
addNum(num: int) void
findMedian() float
}
MedianFinder : max_heap stores_negative_values
MedianFinder : min_heap stores_positive_values
Class diagram for binary tree solutions (invert tree and count complete nodes)classDiagram
class TreeNode {
int val
TreeNode left
TreeNode right
__init__(val: int, left: TreeNode, right: TreeNode)
}
class SolutionInvertTree {
invertTree(root: TreeNode) TreeNode
}
class SolutionCountNodes {
countNodes(root: TreeNode) int
get_height(node: TreeNode) int
}
SolutionInvertTree --> TreeNode : manipulates
SolutionCountNodes --> TreeNode : reads_structure
%% Representing LeetCode class names
class SolutionInvertTree as Solution_226
class SolutionCountNodes as Solution_222
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
WalkthroughNew documentation and Python implementations for 16 algorithms covering bit manipulation, graph algorithms, dynamic programming, tree operations, and data structures. Each algorithm includes a detailed explanation file (strategy, complexity, examples) paired with a Python solution file. No modifications to existing code; only new files added. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Areas requiring extra attention:
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes - here's some feedback:
- In both
canFinish(207/01.py) andfindOrder(210/01.py) you’re using a Python list as a queue withpop(0), which is O(n) per pop; consider switching tocollections.dequeand usingpopleft()to keep the BFS truly O(V + E). - In the Word Search II solution (212/01.py),
TrieNode.childrenis an untyped dict anddfsaccessesnode.children[char]directly; adding a type alias for the trie node and annotatingchildrenwould make the data structure clearer and help static analysis catch misuse.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In both `canFinish` (207/01.py) and `findOrder` (210/01.py) you’re using a Python list as a queue with `pop(0)`, which is O(n) per pop; consider switching to `collections.deque` and using `popleft()` to keep the BFS truly O(V + E).
- In the Word Search II solution (212/01.py), `TrieNode.children` is an untyped dict and `dfs` accesses `node.children[char]` directly; adding a type alias for the trie node and annotating `children` would make the data structure clearer and help static analysis catch misuse.
## Individual Comments
### Comment 1
<location> `solutions/207/01.py:14-21` </location>
<code_context>
+ in_degree[course] += 1
+
+ # Find all courses with no prerequisites
+ queue = []
+ for i in range(numCourses):
+ if in_degree[i] == 0:
+ queue.append(i)
+
+ count = 0
+ while queue:
+ course = queue.pop(0)
+ count += 1
+
</code_context>
<issue_to_address>
**suggestion (performance):** Using list.pop(0) for the queue leads to O(n²) behavior; a deque would be more efficient.
Because lists shift all elements on `pop(0)`, each dequeue is O(n), making the overall traversal O(n²) for large `numCourses`. `collections.deque.popleft()` keeps these queue operations O(1).
Suggested implementation:
```python
from collections import deque
class Solution:
```
To fully implement the deque-based queue:
1. Locate the section in `canFinish` where the queue is created and initialized. It likely looks something like:
```python
queue = []
for i in range(numCourses):
if in_degree[i] == 0:
queue.append(i)
```
Change this to:
```python
queue = deque()
for i in range(numCourses):
if in_degree[i] == 0:
queue.append(i)
```
(`append` remains the same; only the type changes.)
2. Locate the loop where elements are dequeued, which should currently look like:
```python
while queue:
course = queue.pop(0)
count += 1
# ...
```
Change the dequeue to use `popleft()`:
```python
while queue:
course = queue.popleft()
count += 1
# ...
```
These changes will ensure the BFS/topological sort uses `collections.deque` with O(1) enqueue/dequeue instead of list `pop(0)` with O(n) behavior.
</issue_to_address>
### Comment 2
<location> `solutions/210/01.py:14-21` </location>
<code_context>
+ in_degree[course] += 1
+
+ # Find all courses with no prerequisites
+ queue = []
+ for i in range(numCourses):
+ if in_degree[i] == 0:
+ queue.append(i)
+
+ count = 0
+ while queue:
+ course = queue.pop(0)
+ count += 1
+
</code_context>
<issue_to_address>
**suggestion (performance):** As in canFinish, using pop(0) on a list for the BFS queue is inefficient.
Here `queue.pop(0)` is O(n) per pop. Using `collections.deque` and `popleft()` would make the BFS queue operations O(1), which scales better for large graphs.
Suggested implementation:
```python
# Find all courses with no prerequisites
queue = deque()
for i in range(numCourses):
if in_degree[i] == 0:
queue.append(i)
count = 0
while queue:
course = queue.popleft()
count += 1
```
To fully implement this change, ensure that `deque` is imported at the top of `solutions/210/01.py`:
```python
from collections import deque
```
If there is already an import section, add this import alongside the others.
</issue_to_address>
### Comment 3
<location> `explanations/190/en.md:6` </location>
<code_context>
+### Strategy (The "Why")
+
+**1.1 Constraints & Complexity:**
+- **Constraints:** We're working with a 32-bit unsigned integer. The input `n` ranges from 0 to 2^31 - 2 and is always even.
+- **Time Complexity:** O(1) - We iterate exactly 32 times regardless of input size.
+- **Space Complexity:** O(1) - We use only a constant amount of extra space.
</code_context>
<issue_to_address>
**issue:** Constraints for `n` (range and "always even") look incorrect for this problem.
The constraint line describes `n` as 0 to 2^31 - 2 and always even, which doesn’t match a 32-bit unsigned integer or typical bit-reversal specs. Please adjust the upper bound (e.g., 2^31 - 1 or 2^32 - 1, per the intended spec) and drop the “always even” condition unless the problem explicitly requires it.
</issue_to_address>
### Comment 4
<location> `explanations/191/en.md:6-9` </location>
<code_context>
+### Strategy (The "Why")
+
+**1.1 Constraints & Complexity:**
+- **Constraints:** The input `n` is a positive integer from 1 to 2^31 - 1.
+- **Time Complexity:** O(k) where k is the number of set bits (1s) in the binary representation. In worst case, this is O(32) = O(1) for 32-bit integers.
+- **Space Complexity:** O(1) - We use only a constant amount of extra space.
+- **Edge Case:** If `n = 0`, there are no set bits, so the result is 0.
+
+**1.2 High-level approach:**
</code_context>
<issue_to_address>
**issue:** Constraints and edge-case description are inconsistent regarding whether `n = 0` is allowed.
The constraints say `n` is in [1, 2^31 - 1], but the edge-case section handles `n = 0`. Please either update the constraints to include 0 or remove/rephrase the `n = 0` case so the allowed range and examples align.
</issue_to_address>
### Comment 5
<location> `solutions/207/01.py:14` </location>
<code_context>
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
# Build adjacency list
graph = [[] for _ in range(numCourses)]
in_degree = [0] * numCourses
for course, prereq in prerequisites:
graph[prereq].append(course)
in_degree[course] += 1
# Find all courses with no prerequisites
queue = []
for i in range(numCourses):
if in_degree[i] == 0:
queue.append(i)
count = 0
while queue:
course = queue.pop(0)
count += 1
# Reduce in-degree of dependent courses
for next_course in graph[course]:
in_degree[next_course] -= 1
if in_degree[next_course] == 0:
queue.append(next_course)
return count == numCourses
</code_context>
<issue_to_address>
**issue (code-quality):** Convert for loop into list comprehension ([`list-comprehension`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/list-comprehension/))
</issue_to_address>
### Comment 6
<location> `solutions/210/01.py:14` </location>
<code_context>
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
# Build adjacency list
graph = [[] for _ in range(numCourses)]
in_degree = [0] * numCourses
for course, prereq in prerequisites:
graph[prereq].append(course)
in_degree[course] += 1
# Find all courses with no prerequisites
queue = []
for i in range(numCourses):
if in_degree[i] == 0:
queue.append(i)
res = []
while queue:
course = queue.pop(0)
res.append(course)
# Reduce in-degree of dependent courses
for next_course in graph[course]:
in_degree[next_course] -= 1
if in_degree[next_course] == 0:
queue.append(next_course)
return res if len(res) == numCourses else []
</code_context>
<issue_to_address>
**issue (code-quality):** Convert for loop into list comprehension ([`list-comprehension`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/list-comprehension/))
</issue_to_address>
### Comment 7
<location> `solutions/2211/01.py:7-18` </location>
<code_context>
def countCollisions(self, directions: str) -> int:
# Remove leading L's (moving left, will never collide)
# Remove trailing R's (moving right, will never collide)
# Only cars in the middle section will collide
directions = directions.lstrip('L').rstrip('R')
if not directions:
return 0
res = 0
# Count all non-stationary cars in the middle section
# Each R or L in the middle will eventually collide
for char in directions:
if char != 'S':
res += 1
return res
</code_context>
<issue_to_address>
**suggestion (code-quality):** We've found these issues:
- Convert for loop into call to sum() ([`sum-comprehension`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/sum-comprehension/))
- Lift code into else after jump in control flow ([`reintroduce-else`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/reintroduce-else/))
- Replace if statement with if expression ([`assign-if-exp`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/assign-if-exp/))
- Inline variable that is immediately returned ([`inline-immediately-returned-variable`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/inline-immediately-returned-variable/))
```suggestion
return 0 if not directions else sum(1 for char in directions if char != 'S')
```
</issue_to_address>
### Comment 8
<location> `solutions/224/01.py:20` </location>
<code_context>
def calculate(self, s: str) -> int:
stack = []
res = 0
num = 0
sign = 1
for char in s:
if char.isdigit():
num = num * 10 + int(char)
elif char == '+':
res += sign * num
num = 0
sign = 1
elif char == '-':
res += sign * num
num = 0
sign = -1
elif char == '(':
stack.append(res)
stack.append(sign)
res = 0
sign = 1
elif char == ')':
res += sign * num
num = 0
res *= stack.pop() # pop sign
res += stack.pop() # pop previous result
return res + sign * num
</code_context>
<issue_to_address>
**issue (code-quality):** Merge consecutive list appends into a single extend ([`merge-list-appends-into-extend`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/merge-list-appends-into-extend/))
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| queue = [] | ||
| for i in range(numCourses): | ||
| if in_degree[i] == 0: | ||
| queue.append(i) | ||
|
|
||
| count = 0 | ||
| while queue: | ||
| course = queue.pop(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (performance): Using list.pop(0) for the queue leads to O(n²) behavior; a deque would be more efficient.
Because lists shift all elements on pop(0), each dequeue is O(n), making the overall traversal O(n²) for large numCourses. collections.deque.popleft() keeps these queue operations O(1).
Suggested implementation:
from collections import deque
class Solution:To fully implement the deque-based queue:
-
Locate the section in
canFinishwhere the queue is created and initialized. It likely looks something like:queue = [] for i in range(numCourses): if in_degree[i] == 0: queue.append(i)
Change this to:
queue = deque() for i in range(numCourses): if in_degree[i] == 0: queue.append(i)
(
appendremains the same; only the type changes.) -
Locate the loop where elements are dequeued, which should currently look like:
while queue: course = queue.pop(0) count += 1 # ...
Change the dequeue to use
popleft():while queue: course = queue.popleft() count += 1 # ...
These changes will ensure the BFS/topological sort uses collections.deque with O(1) enqueue/dequeue instead of list pop(0) with O(n) behavior.
| queue = [] | ||
| for i in range(numCourses): | ||
| if in_degree[i] == 0: | ||
| queue.append(i) | ||
|
|
||
| res = [] | ||
| while queue: | ||
| course = queue.pop(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (performance): As in canFinish, using pop(0) on a list for the BFS queue is inefficient.
Here queue.pop(0) is O(n) per pop. Using collections.deque and popleft() would make the BFS queue operations O(1), which scales better for large graphs.
Suggested implementation:
# Find all courses with no prerequisites
queue = deque()
for i in range(numCourses):
if in_degree[i] == 0:
queue.append(i)
count = 0
while queue:
course = queue.popleft()
count += 1To fully implement this change, ensure that deque is imported at the top of solutions/210/01.py:
from collections import dequeIf there is already an import section, add this import alongside the others.
| ### Strategy (The "Why") | ||
|
|
||
| **1.1 Constraints & Complexity:** | ||
| - **Constraints:** We're working with a 32-bit unsigned integer. The input `n` ranges from 0 to 2^31 - 2 and is always even. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: Constraints for n (range and "always even") look incorrect for this problem.
The constraint line describes n as 0 to 2^31 - 2 and always even, which doesn’t match a 32-bit unsigned integer or typical bit-reversal specs. Please adjust the upper bound (e.g., 2^31 - 1 or 2^32 - 1, per the intended spec) and drop the “always even” condition unless the problem explicitly requires it.
| - **Constraints:** The input `n` is a positive integer from 1 to 2^31 - 1. | ||
| - **Time Complexity:** O(k) where k is the number of set bits (1s) in the binary representation. In worst case, this is O(32) = O(1) for 32-bit integers. | ||
| - **Space Complexity:** O(1) - We use only a constant amount of extra space. | ||
| - **Edge Case:** If `n = 0`, there are no set bits, so the result is 0. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: Constraints and edge-case description are inconsistent regarding whether n = 0 is allowed.
The constraints say n is in [1, 2^31 - 1], but the edge-case section handles n = 0. Please either update the constraints to include 0 or remove/rephrase the n = 0 case so the allowed range and examples align.
|
|
||
| if not directions: | ||
| return 0 | ||
|
|
||
| res = 0 | ||
| # Count all non-stationary cars in the middle section | ||
| # Each R or L in the middle will eventually collide | ||
| for char in directions: | ||
| if char != 'S': | ||
| res += 1 | ||
|
|
||
| return res |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (code-quality): We've found these issues:
- Convert for loop into call to sum() (
sum-comprehension) - Lift code into else after jump in control flow (
reintroduce-else) - Replace if statement with if expression (
assign-if-exp) - Inline variable that is immediately returned (
inline-immediately-returned-variable)
| if not directions: | |
| return 0 | |
| res = 0 | |
| # Count all non-stationary cars in the middle section | |
| # Each R or L in the middle will eventually collide | |
| for char in directions: | |
| if char != 'S': | |
| res += 1 | |
| return res | |
| return 0 if not directions else sum(1 for char in directions if char != 'S') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (7)
solutions/221/01.py (1)
1-22: LGTM!Correct DP implementation for the maximal square problem. The recurrence relation
dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1is properly applied, and edge cases (empty matrix, boundary cells) are handled correctly.Optional: Space can be optimized from O(m×n) to O(n) by keeping only the previous row, but the current implementation is clear and maintainable.
solutions/2211/01.py (1)
1-19: LGTM!Clever solution leveraging the insight that leading 'L's and trailing 'R's never collide. The approach is correct and efficient with O(n) time complexity.
Optional simplification: The loop on lines 14-16 can be replaced with a more Pythonic one-liner:
- res = 0 - # Count all non-stationary cars in the middle section - # Each R or L in the middle will eventually collide - for char in directions: - if char != 'S': - res += 1 - - return res + # Count all non-stationary cars in the middle section + return len(directions) - directions.count('S')explanations/221/en.md (2)
28-35: Specify a language for the example code blockThe example matrix is in a fenced block without a language, which markdownlint flags and also misses out on syntax highlighting.
You can mark it as Python-like data:
-Example matrix: -``` -[["1","0","1","0","0"], - ["1","0","1","1","1"], - ["1","1","1","1","1"], - ["1","0","0","1","0"]] -``` +Example matrix: +```python +[["1", "0", "1", "0", "0"], + ["1", "0", "1", "1", "1"], + ["1", "1", "1", "1", "1"], + ["1", "0", "0", "1", "0"]] +```This should clear the fenced-code-language warning and makes the snippet clearer.
44-50: Wrap DP index expressions in backticks to avoid link‑style parsingThe table header row uses values like
matrix[i][j]anddp[i-1][j-1]without backticks, which markdownlint interprets as reference links ([j],[j-1]) and warns about missing definitions.You can both improve readability and silence MD052 by wrapping these in code spans:
-| (i,j) | matrix[i][j] | dp[i-1][j] | dp[i][j-1] | dp[i-1][j-1] | dp[i][j] | res | +| (i, j) | `matrix[i][j]` | `dp[i-1][j]` | `dp[i][j-1]` | `dp[i-1][j-1]` | `dp[i][j]` | `res` |(Adjust spacing/format as you prefer; the key point is adding backticks around the index expressions.)
explanations/212/en.md (1)
48-51: Wrapboard[i][j]in backticks to avoid markdown reference warningsThe bullet:
If board[i][j] matches a trie root child, start DFS
is likely triggering markdownlint’s “missing reference” warning for
[j]. You can fix that and make it clearer by using a code span:-- For each cell (i, j): -- - If board[i][j] matches a trie root child, start DFS +- For each cell (i, j): +- If `board[i][j]` matches a trie root child, start DFS(Similarly, you can wrap other indexed expressions in backticks if you want consistent formatting.)
solutions/207/01.py (1)
4-30: Consider usingcollections.dequefor O(1) queue operations.The topological sort logic is correct. However,
queue.pop(0)on a list is O(n), degrading the overall time complexity from O(V+E) to O(V²+E) when processing many courses. For better performance, usecollections.dequewithpopleft().Apply this diff:
+from collections import deque + class Solution: def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: # Build adjacency list graph = [[] for _ in range(numCourses)] in_degree = [0] * numCourses for course, prereq in prerequisites: graph[prereq].append(course) in_degree[course] += 1 # Find all courses with no prerequisites - queue = [] + queue = deque() for i in range(numCourses): if in_degree[i] == 0: queue.append(i) count = 0 while queue: - course = queue.pop(0) + course = queue.popleft() count += 1 # Reduce in-degree of dependent courses for next_course in graph[course]: in_degree[next_course] -= 1 if in_degree[next_course] == 0: queue.append(next_course) return count == numCoursessolutions/210/01.py (1)
4-30: Consider usingcollections.dequefor O(1) queue operations.The topological sort implementation is correct. However,
queue.pop(0)on a list is O(n), which degrades the overall complexity from O(V+E) to O(V²+E). Usingcollections.dequewithpopleft()provides O(1) removal.Apply this diff:
+from collections import deque + class Solution: def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]: # Build adjacency list graph = [[] for _ in range(numCourses)] in_degree = [0] * numCourses for course, prereq in prerequisites: graph[prereq].append(course) in_degree[course] += 1 # Find all courses with no prerequisites - queue = [] + queue = deque() for i in range(numCourses): if in_degree[i] == 0: queue.append(i) res = [] while queue: - course = queue.pop(0) + course = queue.popleft() res.append(course) # Reduce in-degree of dependent courses for next_course in graph[course]: in_degree[next_course] -= 1 if in_degree[next_course] == 0: queue.append(next_course) return res if len(res) == numCourses else []
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (30)
explanations/190/en.md(1 hunks)explanations/191/en.md(1 hunks)explanations/201/en.md(1 hunks)explanations/202/en.md(1 hunks)explanations/207/en.md(1 hunks)explanations/209/en.md(1 hunks)explanations/210/en.md(1 hunks)explanations/211/en.md(1 hunks)explanations/212/en.md(1 hunks)explanations/221/en.md(1 hunks)explanations/2211/en.md(1 hunks)explanations/222/en.md(1 hunks)explanations/224/en.md(1 hunks)explanations/226/en.md(1 hunks)explanations/295/en.md(1 hunks)solutions/190/01.py(1 hunks)solutions/191/01.py(1 hunks)solutions/201/01.py(1 hunks)solutions/202/01.py(1 hunks)solutions/207/01.py(1 hunks)solutions/209/01.py(1 hunks)solutions/210/01.py(1 hunks)solutions/211/01.py(1 hunks)solutions/212/01.py(1 hunks)solutions/221/01.py(1 hunks)solutions/2211/01.py(1 hunks)solutions/222/01.py(1 hunks)solutions/224/01.py(1 hunks)solutions/226/01.py(1 hunks)solutions/295/01.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
solutions/190/01.py (2)
solutions/191/01.py (1)
Solution(1-8)solutions/201/01.py (1)
Solution(1-10)
solutions/207/01.py (1)
solutions/210/01.py (1)
Solution(3-30)
solutions/210/01.py (1)
solutions/207/01.py (1)
Solution(3-30)
solutions/212/01.py (1)
solutions/211/01.py (2)
TrieNode(1-4)dfs(19-32)
solutions/211/01.py (1)
solutions/212/01.py (2)
TrieNode(1-4)dfs(23-47)
🪛 LanguageTool
explanations/209/en.md
[grammar] ~12-~12: Use a hyphen to join words.
Context: ...roach:** The goal is to find the minimal length subarray whose sum is at least `t...
(QB_NEW_EN_HYPHEN)
explanations/201/en.md
[style] ~15-~15: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...where n is the range size, which can be very large. - Optimized Strategy: Find the com...
(EN_WEAK_ADJECTIVE)
explanations/224/en.md
[style] ~23-~23: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...sign, reset number, and update sign. 4. For '(', push current result and sign to st...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~24-~24: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ign to stack, reset result and sign. 5. For ')', add current number to result, then...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
🪛 markdownlint-cli2 (0.18.1)
explanations/212/en.md
7-7: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
7-7: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
15-15: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
15-15: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
49-49: Reference links and images should use a label that is defined
Missing link or image reference definition: "j"
(MD052, reference-links-images)
explanations/221/en.md
15-15: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
15-15: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
30-30: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
44-44: Reference links and images should use a label that is defined
Missing link or image reference definition: "j"
(MD052, reference-links-images)
44-44: Reference links and images should use a label that is defined
Missing link or image reference definition: "j"
(MD052, reference-links-images)
44-44: Reference links and images should use a label that is defined
Missing link or image reference definition: "j"
(MD052, reference-links-images)
44-44: Reference links and images should use a label that is defined
Missing link or image reference definition: "j-1"
(MD052, reference-links-images)
44-44: Reference links and images should use a label that is defined
Missing link or image reference definition: "j-1"
(MD052, reference-links-images)
explanations/211/en.md
31-31: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🪛 Ruff (0.14.7)
solutions/222/01.py
11-11: Undefined name TreeNode
(F821)
solutions/226/01.py
11-11: Undefined name TreeNode
(F821)
11-11: Undefined name TreeNode
(F821)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Sourcery review
🔇 Additional comments (19)
explanations/226/en.md (1)
1-66: LGTM!The explanation is well-structured with clear complexity analysis, decomposition steps, and a helpful trace walkthrough table. The visual representation of the tree before and after inversion aids understanding.
solutions/191/01.py (1)
1-9: LGTM!Clean implementation of Brian Kernighan's algorithm. The
n &= n - 1trick efficiently clears the rightmost set bit, making this O(k) where k is the number of set bits—optimal for this problem.solutions/190/01.py (1)
1-10: LGTM!Correct bit-reversal implementation. The approach of extracting each bit at position
iand placing it at position31 - iis clear and efficient. O(32) = O(1) time complexity.explanations/191/en.md (1)
5-50: Explanation aligns well with the implemented algorithmConstraints, complexity (O(k) with k set bits), and the
n & (n - 1)walkthrough are accurate and match the typical solution. Nothing to change here.explanations/224/en.md (1)
19-60: Calculator walkthrough and stack logic look solidThe decomposition and the trace for
(1+(4+5+2)-3)+(6+8)correctly reflect the standard single-pass stack solution. The description of pushing[res, sign]on'('and combining on')'matches the usual implementation.solutions/201/01.py (1)
1-10: Range AND implementation is correct and idiomaticUsing common-prefix via right shifts and then shifting back (
left << shift) is the canonical O(1) solution for this problem; the loop condition and state updates are all correct.explanations/2211/en.md (1)
5-51: Collision-counting explanation matches the optimized approachTrimming escaping
L/Rcars and then counting non‑'S'cars in the middle is exactly the intended O(n) strategy, and the"RLRSLL"walkthrough is consistent with the final answer of 5.solutions/224/01.py (1)
1-30: Calculator implementation looks correct and complete.Stack handling, sign management, and digit accumulation all align with the standard solution for LeetCode 224, including nested parentheses and unary +/- cases. No changes needed.
solutions/295/01.py (1)
1-27: Two‑heap median structure is correctly implemented.Heap partitioning, rebalancing, and median calculation are all consistent with the canonical O(log n) / O(1) approach for LeetCode 295. No adjustments needed.
solutions/212/01.py (1)
1-55: Trie + DFS solution for Word Search II is sound and efficient.Trie construction, DFS traversal with in‑place marking, de‑duplication via
curr_node.word = None, and leaf pruning are all correctly wired and match the standard optimized pattern for LeetCode 212. Looks good.explanations/201/en.md (1)
5-49: Range AND explanation correctly matches the standard common-prefix solution.The description of shifting
leftandrightuntil they match, trackingshift, and then left-shifting back is accurate and well-aligned with the typical O(log n) implementation for LeetCode 201. No changes needed.solutions/211/01.py (1)
1-35: Trie-basedWordDictionaryimplementation is correct.
addWordand DFS-basedsearch(with '.' wildcard support) follow the standard LeetCode 211 pattern and correctly handle branching and termination conditions. Looks good as-is.solutions/222/01.py (1)
11-31: LGTM! Efficient complete binary tree node counting.The implementation correctly leverages the complete binary tree property by comparing left and right subtree heights to determine which subtree is full, then recursively counting only the incomplete subtree. The bit-shift operation efficiently calculates 2^height.
solutions/202/01.py (1)
2-18: LGTM! Clean happy number implementation.The cycle detection using a set is correct, and the digit sum-of-squares calculation is properly implemented. The algorithm correctly identifies happy numbers by detecting either convergence to 1 or a cycle.
solutions/209/01.py (1)
4-17: LGTM! Correct sliding window implementation.The two-pointer sliding window approach efficiently finds the minimal subarray length with sum ≥ target in O(n) time. The logic correctly expands the window rightward and contracts leftward while maintaining the minimum length.
explanations/209/en.md (1)
1-56: LGTM! Comprehensive documentation.The explanation thoroughly covers the sliding window strategy with clear complexity analysis, edge cases, and a detailed step-by-step walkthrough. The structure aligns well with the repository's documentation format.
explanations/202/en.md (1)
1-53: LGTM! Clear and thorough explanation.The documentation effectively explains the happy number algorithm with proper coverage of cycle detection, complexity analysis, and a detailed walkthrough. The structure is consistent with the repository's documentation standards.
explanations/207/en.md (1)
1-54: LGTM! Well-structured explanation of topological sorting.The documentation clearly explains Kahn's algorithm for cycle detection in course prerequisites, with proper complexity analysis and a step-by-step example. The structure follows the repository's documentation format effectively.
explanations/210/en.md (1)
1-55: Comprehensive and accurate explanation of Kahn's algorithm for topological sorting.The explanation is well-structured, technically correct, and pedagogically clear. The strategy section effectively contrasts brute force vs. optimized approaches, the complexity analysis is accurate (O(V+E) time and space), and the step-by-step trace table with the concrete example [0,1,2,3] is excellent for understanding the algorithm flow. The in-degree calculations and graph construction are correct given the prerequisite format
[course, prerequisite].The format follows the stated repository structure (strategy, complexity, examples, walkthrough).
Optional suggestion for polish: Consider adding a brief note at the very beginning mentioning the problem context (e.g., "Find a valid course ordering given prerequisites, or detect cycles") to help readers immediately understand what problem we're solving before diving into the algorithm.
| **1.1 Constraints & Complexity:** | ||
| - **Constraints:** We're working with a 32-bit unsigned integer. The input `n` ranges from 0 to 2^31 - 2 and is always even. | ||
| - **Time Complexity:** O(1) - We iterate exactly 32 times regardless of input size. | ||
| - **Space Complexity:** O(1) - We use only a constant amount of extra space. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the constraints description (incorrect range and “always even”).
The line
The input
nranges from 0 to 2^31 - 2 and is always even.
doesn’t match the actual problem: the input is just a 32‑bit unsigned integer; it is not guaranteed to be even, and the upper bound here is off. Suggest rephrasing to something like:
Constraints: We’re working with a 32‑bit unsigned integer
n(i.e.,0 <= n < 2^32).
This keeps the explanation accurate without over‑constraining the input.
🤖 Prompt for AI Agents
In explanations/190/en.md around lines 5 to 8, the constraints sentence
incorrectly states the input range and that n is always even; update it to
correctly describe the input as a 32-bit unsigned integer with range 0 <= n <
2^32 and remove any claim that n is always even (or otherwise state parity is
unconstrained), keeping the Time and Space Complexity lines unchanged.
| **1.1 Constraints & Complexity:** | ||
| - **Constraints:** Word length is 1 to 25, and there are at most 10^4 calls to `addWord` and `search`. Search queries have at most 2 dots. | ||
| - **Time Complexity:** | ||
| - `addWord`: O(m) where m is the word length | ||
| - `search`: O(m * 26^k) in worst case where k is the number of dots, but typically much better | ||
| - **Space Complexity:** O(N * M) where N is the number of words and M is the average word length. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarify search constraints ('.' is not limited to 2 occurrences)
The line:
Search queries have at most 2 dots.
is misleading for this problem; the search pattern can contain '.' in any positions up to the word length, and the algorithm/complexity discussion already uses a generic k = number of dots.
I’d suggest generalizing the constraints:
- **Constraints:** Word length is 1 to 25, and there are at most 10^4 calls to `addWord` and `search`. Search queries have at most 2 dots.
+ **Constraints:** Word length is 1 to 25, and there are at most 10^4 calls to `addWord` and `search`. Search queries may contain the `'.'` wildcard in any positions.This keeps the explanation accurate without over-restricting the problem statement.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| **1.1 Constraints & Complexity:** | |
| - **Constraints:** Word length is 1 to 25, and there are at most 10^4 calls to `addWord` and `search`. Search queries have at most 2 dots. | |
| - **Time Complexity:** | |
| - `addWord`: O(m) where m is the word length | |
| - `search`: O(m * 26^k) in worst case where k is the number of dots, but typically much better | |
| - **Space Complexity:** O(N * M) where N is the number of words and M is the average word length. | |
| **1.1 Constraints & Complexity:** | |
| - **Constraints:** Word length is 1 to 25, and there are at most 10^4 calls to `addWord` and `search`. Search queries may contain the `'.'` wildcard in any positions. | |
| - **Time Complexity:** | |
| - `addWord`: O(m) where m is the word length | |
| - `search`: O(m * 26^k) in worst case where k is the number of dots, but typically much better | |
| - **Space Complexity:** O(N * M) where N is the number of words and M is the average word length. |
🤖 Prompt for AI Agents
explanations/211/en.md around lines 5 to 10: the current text incorrectly states
"Search queries have at most 2 dots." Update this to remove the hard cap and
instead state that search patterns may contain dots in any positions up to the
word length (e.g., "Search queries may contain '.' in any positions up to the
word length; let k be the number of dots") and ensure the Time Complexity
paragraph references k as the number of dots to match the rest of the section.
| **2.1 Initialization & Example Setup:** | ||
| Example tree: `[1,2,3,4,5,6]` (complete binary tree with 6 nodes) | ||
|
|
||
| Root = 1, left = 2, right = 3 | ||
|
|
||
| **2.2 Start Checking:** | ||
| Calculate left height from root.left (node 2): follow left children → 4 → None, height = 2 | ||
| Calculate right height from root.right (node 3): follow left children → None, height = 0 | ||
|
|
||
| **2.3 Trace Walkthrough:** | ||
|
|
||
| | Node | Left Height | Right Height | Action | | ||
| |------|-------------|---------------|--------| | ||
| | 1 | 2 | 0 | Heights differ, right is full. Count = 2^0 + countNodes(left) | | ||
| | 2 | 1 | 0 | Heights differ, right is full. Count = 2^0 + countNodes(left) | | ||
| | 4 | 0 | 0 | Heights equal, left is full. Count = 2^0 + countNodes(right) | | ||
| | 5 | 0 | 0 | Base case, return 1 | | ||
|
|
||
| **2.4 Increment and Loop:** | ||
| Recursively: | ||
| - If left_height == right_height: return (1 << left_height) + countNodes(right) | ||
| - Else: return (1 << right_height) + countNodes(left) | ||
|
|
||
| **2.5 Return Result:** | ||
| Total count = 1 (root) + 1 (node 2) + 1 (node 4) + 1 (node 5) + 1 (node 3) + 1 (node 6) = 6 nodes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align the walkthrough heights/actions with the described algorithm.
In the example with tree [1,2,3,4,5,6], the stated heights and actions in the walkthrough are inconsistent with a complete-tree structure and with the earlier description:
- Line 35–36 describe the right height from
root.rightas going directly toNonewith height 0, which doesn’t match a tree where node3has a left child6. - The table row for node
1(and subsequent rows) then apply formulas based on these mismatched heights.
The high-level algorithm you describe (using subtree heights to decide which side is full and recursing on the other) is correct, but the concrete numbers in this trace should be recomputed so that:
- Left/right heights reflect the actual example tree structure and the height function you intend to use.
- The “Action” column corresponds to the real branch (
left_height == right_heightvs. not) taken at each node.
Updating the table to show a consistent run of the algorithm will make the explanation much clearer.
| After adding 1, 2, 3: | ||
| - `max_heap = [-2, -1]`, `min_heap = [3]` | ||
| - Median = (-(-2) + 3) / 2 = (2 + 3) / 2 = 2.5 (if equal sizes) | ||
| - Or median = -(-2) = 2 (if max_heap is larger) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix median example for the two‑heap walkthrough
For the example after adding 1, 2, 3, the median is 2, not 2.5. The current bullets mix the odd-length example with the even-length formula, which is confusing.
Consider updating this section to clearly distinguish odd vs even counts, e.g.:
-After adding 1, 2, 3:
-- `max_heap = [-2, -1]`, `min_heap = [3]`
-- Median = (-(-2) + 3) / 2 = (2 + 3) / 2 = 2.5 (if equal sizes)
-- Or median = -(-2) = 2 (if max_heap is larger)
+After adding 1, 2, 3:
+- `max_heap = [-2, -1]`, `min_heap = [3]`
+- We have an odd number of elements, so the median is the top of the larger heap: `-(-2) = 2`.
+
+For an even number of elements (e.g., `[1, 2, 3, 4]` with
+`max_heap = [-2, -1]` and `min_heap = [3, 4]`), the median is
+the average of both tops: `(2 + 3) / 2 = 2.5`.This keeps both behaviors clear and consistent with the example data.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| After adding 1, 2, 3: | |
| - `max_heap = [-2, -1]`, `min_heap = [3]` | |
| - Median = (-(-2) + 3) / 2 = (2 + 3) / 2 = 2.5 (if equal sizes) | |
| - Or median = -(-2) = 2 (if max_heap is larger) | |
| After adding 1, 2, 3: | |
| - `max_heap = [-2, -1]`, `min_heap = [3]` | |
| - We have an odd number of elements, so the median is the top of the larger heap: `-(-2) = 2`. | |
| For an even number of elements (e.g., `[1, 2, 3, 4]` with | |
| `max_heap = [-2, -1]` and `min_heap = [3, 4]`), the median is | |
| the average of both tops: `(2 + 3) / 2 = 2.5`. |
🤖 Prompt for AI Agents
In explanations/295/en.md around lines 52 to 55, the median example after adding
1, 2, 3 incorrectly shows 2.5 by mixing the even-length formula with an
odd-length state; update the bullets to state the heap contents and then clearly
show the odd-count median rule: max_heap = [-2, -1], min_heap = [3], median =
top of max_heap => -(-2) = 2; separately add a brief note demonstrating the
even-count case (when heaps are equal size) where median = (top_max + top_min)/2
to avoid confusion.
| class Solution: | ||
| def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: | ||
| if not root: | ||
| return None | ||
|
|
||
| root.left, root.right = root.right, root.left | ||
|
|
||
| invertTree(root.left) | ||
| invertTree(root.right) | ||
|
|
||
| return root | ||
| # Swap left and right children | ||
| root.left, root.right = root.right, root.left | ||
|
|
||
| # Recursively invert subtrees | ||
| self.invertTree(root.left) | ||
| self.invertTree(root.right) | ||
|
|
||
| return root |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix undefined TreeNode in type hints (runtime NameError).
TreeNode is only present in a commented stub, but used in annotations:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:Without a real TreeNode definition or string/“future” annotations, this will raise a NameError when the function is defined.
A minimal fix that keeps the LeetCode-style commented stub but makes the file valid Python is to use forward-referenced string annotations:
-from typing import Optional
+from typing import Optional
class Solution:
- def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
+ def invertTree(self, root: Optional["TreeNode"]) -> Optional["TreeNode"]:Alternatively, you could add from __future__ import annotations at the top, but using quoted "TreeNode" is enough here.
🧰 Tools
🪛 Ruff (0.14.7)
11-11: Undefined name TreeNode
(F821)
11-11: Undefined name TreeNode
(F821)
🤖 Prompt for AI Agents
In solutions/226/01.py around lines 10 to 22 the type hints use TreeNode which
is not defined at runtime causing a NameError; update the annotations to use
forward-referenced string types (e.g. "TreeNode") or add from __future__ import
annotations at the top of the file so the annotations are not evaluated at
function definition time, then run a quick lint/type check to ensure no other
undefined names remain.
Summary
This PR adds solutions and explanations for 15 LeetCode problems covering various topics including bit manipulation, graph algorithms, dynamic programming, trees, and data structures.
Problems Added
2211. Count Collisions on a Road (Medium)
190. Reverse Bits (Easy)
191. Number of 1 Bits (Easy)
n & (n-1)trick to remove rightmost set bit, count iterations201. Bitwise AND of Numbers Range (Medium)
202. Happy Number (Easy)
207. Course Schedule (Medium)
209. Minimum Size Subarray Sum (Medium)
210. Course Schedule II (Medium)
211. Design Add and Search Words Data Structure (Medium)
212. Word Search II (Hard)
221. Maximal Square (Medium)
222. Count Complete Tree Nodes (Easy)
224. Basic Calculator (Hard)
226. Invert Binary Tree (Easy)
295. Find Median from Data Stream (Hard)
Files Changed
solutions/<problem-number>/01.pyexplanations/<problem-number>/en.mdAll explanations follow the structured format defined in the workflow rules, including strategy, complexity analysis, and step-by-step walkthroughs.
Summary by Sourcery
Add Python solutions and accompanying English explanations for multiple LeetCode problems across arrays, graphs, trees, bit manipulation, and data structures, and align an existing solution with the LeetCode class-based interface.
New Features:
Enhancements:
Documentation:
Summary by CodeRabbit
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.