docs(docs): add Approach diagrams and Explanation sections to LeetCode problem documentation

This commit is contained in:
Prad Nukala committed 2026-09-21 15:53:21 -04:00
1 parent b8c779903f
commit 23eb71d387
19 files changed
+439

No files matched your search

@@ -21,6 +21,20 @@ sidebar:
- `1 <= k <= nums.length <= 10^5` - `1 <= k <= nums.length <= 10^5`
- `-10^4 <= nums[i] <= 10^4` - `-10^4 <= nums[i] <= 10^4`
## Approach
```mermaid
flowchart TD
S(["findKthLargest(nums, k)"]) --> F{"more i in range(len(nums))?"}
F -- yes --> N["nums[i] = -nums[i] — negate so the min-heap acts as a max-heap"]
N --> F
F -- no --> H["heapq.heapify(nums)"]
H --> W{"more _ in range(k - 1)?"}
W -- yes --> P["heapq.heappop(nums) — discard the k-1 largest"]
P --> W
W -- no --> E(["return -heapq.heappop(nums)"])
```
## Solution ## Solution
```py ```py
@@ -39,3 +53,7 @@ class Solution:
return -heapq.heappop(nums) return -heapq.heappop(nums)
``` ```
## Explanation
<YouTube id="XEmy13g1Qxc" title="Kth Largest Element in an Array - Quick Select - Leetcode 215 - Python" />
@@ -27,6 +27,27 @@ Could you write a generalized algorithm to work on any possible set of character
- `0 <= strs[i].length <= 200` - `0 <= strs[i].length <= 200`
- `strs[i]` contains any possible characters out of 256 valid ASCII characters. - `strs[i]` contains any possible characters out of 256 valid ASCII characters.
## Approach
::::warning
The diagram traces the code below literally. That code does not solve the problem: both `encode` and `decode` have only a docstring for a body, so each returns `None` and `codec.decode(codec.encode(strs))` yields `None` instead of `strs`.
::::
```mermaid
flowchart TD
subgraph state["state — Codec holds no fields"]
X["Codec() — nothing is stored between encode and decode"]
end
subgraph encode["encode(strs)"]
E1["docstring only — no statement runs"] --> E2(["return None"])
end
subgraph decode["decode(s)"]
D1["docstring only — no statement runs"] --> D2(["return None"])
end
state --> encode
state --> decode
```
## Solution ## Solution
```py ```py
@@ -46,3 +67,7 @@ class Codec:
# codec = Codec() # codec = Codec()
# codec.decode(codec.encode(strs)) # codec.decode(codec.encode(strs))
``` ```
## Explanation
<YouTube id="B1k_sxOSgv8" title="Encode and Decode Strings - Leetcode 271 - Python" />
@@ -22,6 +22,22 @@ sidebar:
- `1 <= n <= 20` - `1 <= n <= 20`
- `-1000 <= matrix[i][j] <= 1000` - `-1000 <= matrix[i][j] <= 1000`
## Approach
```mermaid
flowchart TD
S(["rotate(matrix)"]) --> N["n = len(matrix)"]
N --> F{"more r in range(n)?"}
F -- yes --> G{"more c in range(r + 1, n)?"}
G -- yes --> T["swap matrix[r][c] and matrix[c][r] — transpose across the diagonal"]
T --> G
G -- no --> F
F -- no --> H{"more r in range(n)?"}
H -- yes --> R["matrix[r].reverse() — transpose then mirror is a clockwise turn"]
R --> H
H -- no --> E(["return None — rotated in place"])
```
## Solution ## Solution
```py ```py
@@ -35,3 +51,7 @@ class Solution:
for r in range(n): for r in range(n):
matrix[r].reverse() matrix[r].reverse()
``` ```
## Explanation
<YouTube id="fMSJSS7eO1w" title="Rotate Image - Matrix - Leetcode 48" />
@@ -23,6 +23,24 @@ sidebar:
- `1 <= m, n <= 10` - `1 <= m, n <= 10`
- `-100 <= matrix[i][j] <= 100` - `-100 <= matrix[i][j] <= 100`
## Approach
```mermaid
flowchart TD
S(["spiralOrder(matrix)"]) --> I["res = [], top = 0, bottom = len(matrix) - 1, left = 0, right = len(matrix[0]) - 1"]
I --> W{"top <= bottom and left <= right?"}
W -- no --> E(["return res"])
W -- yes --> T["append matrix[top][c] for c in left..right, then top += 1 — top row, shrink from above"]
T --> R["append matrix[r][right] for r in top..bottom, then right -= 1 — right column"]
R --> B{"top <= bottom?"}
B -- yes --> C["append matrix[bottom][c] for c in right down to left, then bottom -= 1 — bottom row"]
C --> L{"left <= right?"}
B -- no --> L
L -- yes --> D["append matrix[r][left] for r in bottom down to top, then left += 1 — left column"]
D --> W
L -- no --> W
```
## Solution ## Solution
```py ```py
@@ -57,3 +75,7 @@ class Solution:
return res return res
``` ```
## Explanation
<YouTube id="BJnMZNwUk1M" title="Spiral Matrix - Microsoft Interview Question - Leetcode 54" />
@@ -30,6 +30,35 @@ You must do it in place.
- A simple improvement uses O(m + n) space, but still not the best solution. - A simple improvement uses O(m + n) space, but still not the best solution.
- Could you devise a constant space solution? - Could you devise a constant space solution?
## Approach
```mermaid
flowchart TD
S(["setZeroes(matrix)"]) --> I["m = len(matrix), n = len(matrix[0])"]
I --> Z["row0_zero = any(matrix[0][c] == 0), col0_zero = any(matrix[r][0] == 0) — remember before they become markers"]
Z --> F{"more r in range(1, m)?"}
F -- yes --> G{"more c in range(1, n)?"}
G -- yes --> Q{"matrix[r][c] == 0?"}
Q -- yes --> M["matrix[r][0] = 0, matrix[0][c] = 0 — row 0 and column 0 are the marker lists"]
M --> G
Q -- no --> G
G -- no --> F
F -- no --> H{"more r in range(1, m)?"}
H -- yes --> J{"more c in range(1, n)?"}
J -- yes --> K{"matrix[r][0] == 0 or matrix[0][c] == 0?"}
K -- yes --> W["matrix[r][c] = 0"]
W --> J
K -- no --> J
J -- no --> H
H -- no --> A{"row0_zero?"}
A -- yes --> B["matrix[0][c] = 0 for c in range(n)"]
B --> C{"col0_zero?"}
A -- no --> C
C -- yes --> D["matrix[r][0] = 0 for r in range(m)"]
D --> E(["return None — zeroed in place"])
C -- no --> E
```
## Solution ## Solution
```py ```py
@@ -65,3 +94,7 @@ class Solution:
for r in range(m): for r in range(m):
matrix[r][0] = 0 matrix[r][0] = 0
``` ```
## Explanation
<YouTube id="T41rL0L3Pnw" title="Set Matrix Zeroes - In-place - Leetcode 73" />
@@ -23,6 +23,23 @@ sidebar:
- `1 <= k <= points.length <= 10^4` - `1 <= k <= points.length <= 10^4`
- `-10^4 <= xi, yi <= 10^4` - `-10^4 <= xi, yi <= 10^4`
## Approach
```mermaid
flowchart TD
S(["kClosest(points, k)"]) --> I["minHeap = []"]
I --> F{"more x, y in points?"}
F -- yes --> D["dist = x**2 + y**2 — squared distance orders the same as sqrt"]
D --> A["minHeap.append([dist, x, y])"]
A --> F
F -- no --> H["heapq.heapify(minHeap), res = [] — O(n) build, smallest dist on top"]
H --> W{"k > 0?"}
W -- yes --> P["dist, x, y = heapq.heappop(minHeap)"]
P --> R["res.append([x, y]), k -= 1"]
R --> W
W -- no --> E(["return res"])
```
## Solution ## Solution
```py ```py
@@ -46,3 +63,7 @@ class Solution:
return res return res
``` ```
## Explanation
<YouTube id="rI2EBUEMfTk" title="K Closest Points to Origin - Heap / Priority Queue - Leetcode 973 - Python" />
@@ -19,6 +19,44 @@ sidebar:
- `word` and `prefix` consist only of lowercase English letters. - `word` and `prefix` consist only of lowercase English letters.
- At most 3 * 10^4 calls in total will be made to insert, search, and startsWith. - At most 3 * 10^4 calls in total will be made to insert, search, and startsWith.
## Approach
```mermaid
flowchart TD
subgraph state["state — root TrieNode; every node holds a children dict and an endOfWord flag"]
R["root"] --- C["... children[c] ..."] --- L["endOfWord = True — a word ends here"]
end
subgraph insert["insert(word)"]
I1["cur = root"] --> I2{"more c in word?"}
I2 -- yes --> I3{"c not in cur.children?"}
I3 -- yes --> I4["cur.children[c] = TrieNode()"]
I4 --> I5["cur = cur.children[c]"]
I3 -- no --> I5
I5 --> I2
I2 -- no --> I6["cur.endOfWord = True"]
I6 --> I7(["done"])
end
subgraph search["search(word)"]
S1["cur = root"] --> S2{"more c in word?"}
S2 -- yes --> S3{"c not in cur.children?"}
S3 -- yes --> S4(["return False"])
S3 -- no --> S5["cur = cur.children[c]"]
S5 --> S2
S2 -- no --> S6(["return cur.endOfWord — the path exists, but is it a whole word?"])
end
subgraph startsWith["startsWith(prefix)"]
P1["cur = root"] --> P2{"more c in prefix?"}
P2 -- yes --> P3{"c not in cur.children?"}
P3 -- yes --> P4(["return False"])
P3 -- no --> P5["cur = cur.children[c]"]
P5 --> P2
P2 -- no --> P6(["return True — every prefix char had a path"])
end
state --> insert
state --> search
state --> startsWith
```
## Solution ## Solution
```py ```py
@@ -68,3 +106,7 @@ class Trie:
# param_2 = obj.search(word) # param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix) # param_3 = obj.startsWith(prefix)
``` ```
## Explanation
<YouTube id="oobqoCJlHA0" title="Implement Trie (Prefix Tree) - Leetcode 208" />
@@ -27,6 +27,20 @@ sidebar:
- `0 <= Node.val <= 9` - `0 <= Node.val <= 9`
- It is guaranteed that the list represents a number that does not have leading zeros. - It is guaranteed that the list represents a number that does not have leading zeros.
## Approach
```mermaid
flowchart TD
S(["addTwoNumbers(l1, l2)"]) --> I["dummy = ListNode(), carry = 0, curr = dummy — dummy.next will be the head"]
I --> W{"l1 or l2 or carry?"}
W -- no --> E(["return dummy.next"])
W -- yes --> A["s = (l1.val if l1 else 0) + (l2.val if l2 else 0) + carry — a missing digit counts as 0"]
A --> D["carry, val = divmod(s, 10)"]
D --> N["curr.next = ListNode(val), curr = curr.next"]
N --> V["l1 = l1.next if l1 else None, l2 = l2.next if l2 else None"]
V --> W
```
## Solution ## Solution
```py ```py
@@ -55,3 +69,7 @@ class Solution:
return dummy.next return dummy.next
``` ```
## Explanation
<YouTube id="wgFPrzTjm7s" title="Add Two Numbers - Leetcode 2 - Python" />
@@ -30,6 +30,27 @@ sidebar:
- `lists[i]` is sorted in ascending order. - `lists[i]` is sorted in ascending order.
- The sum of lists[i].length will not exceed 10^4. - The sum of lists[i].length will not exceed 10^4.
## Approach
```mermaid
flowchart TD
S(["mergeKLists(lists)"]) --> I["heap = []"]
I --> F{"more i, node in enumerate(lists)?"}
F -- yes --> C{"node?"}
C -- yes --> P["heapq.heappush(heap, (node.val, i, node)) — i breaks ties so nodes are never compared"]
P --> F
C -- no --> F
F -- no --> D["D = ListNode(), cur = D"]
D --> W{"heap?"}
W -- no --> E(["return D.next"])
W -- yes --> O["val, i, node = heapq.heappop(heap) — the smallest head across all lists"]
O --> L["cur.next = node, cur = node, node = node.next"]
L --> N{"node?"}
N -- yes --> Q["heapq.heappush(heap, (node.val, i, node))"]
Q --> W
N -- no --> W
```
## Solution ## Solution
```py ```py
@@ -67,3 +88,7 @@ class Solution:
# Space: O(n) # Space: O(n)
return D.next return D.next
``` ```
## Explanation
<YouTube id="q5a5OiGbT6Q" title="Merge K Sorted Lists - Leetcode 23 - Python" />
@@ -16,6 +16,43 @@ sidebar:
- There will be at most 2 dots in `word` for search queries. - There will be at most 2 dots in `word` for search queries.
- At most 10^4 calls will be made to addWord and search. - At most 10^4 calls will be made to addWord and search.
## Approach
```mermaid
flowchart TD
subgraph state["state — root TrieNode; every node holds a children dict and an endOfWord flag"]
R["root"] --- C["... children[c] ..."] --- L["endOfWord = True — a word ends here"]
end
subgraph addWord["addWord(word)"]
A1["cur = root"] --> A2{"more c in word?"}
A2 -- yes --> A3{"c not in cur.children?"}
A3 -- yes --> A4["cur.children[c] = TrieNode()"]
A4 --> A5["cur = cur.children[c]"]
A3 -- no --> A5
A5 --> A2
A2 -- no --> A6["cur.endOfWord = True"]
A6 --> A7(["done"])
end
subgraph search["search(word)"]
S1["dfs(0, root) — match from index 0 at the root"] --> S2["cur = root"]
S2 --> S3{"more i in range(j, len(word))?"}
S3 -- no --> S4(["return cur.endOfWord"])
S3 -- yes --> S5["c = word[i]"]
S5 --> S6{"c == '.'?"}
S6 -- yes --> S7{"more child in cur.children.values()?"}
S7 -- yes --> S8{"dfs(i + 1, child)? — try the rest of the word from this child"}
S8 -- yes --> S9(["return True"])
S8 -- no --> S7
S7 -- no --> S10(["return False — no child matched the wildcard"])
S6 -- no --> S11{"c not in cur.children?"}
S11 -- yes --> S12(["return False"])
S11 -- no --> S13["cur = cur.children[c]"]
S13 --> S3
end
state --> addWord
state --> search
```
## Solution ## Solution
```py ```py
@@ -63,3 +100,7 @@ class WordDictionary:
# obj.addWord(word) # obj.addWord(word)
# param_2 = obj.search(word) # param_2 = obj.search(word)
``` ```
## Explanation
<YouTube id="BTf05gs_8iU" title="Design Add and Search Words Data Structure - Leetcode 211 - Python" />
@@ -25,6 +25,26 @@ sidebar:
- The number of nodes in the tree is in the range [0, 2000]. - The number of nodes in the tree is in the range [0, 2000].
- `-1000 <= Node.val <= 1000` - `-1000 <= Node.val <= 1000`
## Approach
```mermaid
flowchart TD
S(["levelOrder(root)"]) --> I["res = [], q = deque(), q.append(root)"]
I --> W{"q non-empty?"}
W -- no --> E(["return res"])
W -- yes --> L["qLen = len(q), level = [] — qLen freezes the current level's size"]
L --> F{"more i in range(qLen)?"}
F -- no --> V{"level non-empty?"}
V -- yes --> A["res.append(level)"]
A --> W
V -- no --> W
F -- yes --> P["node = q.popleft()"]
P --> N{"node is not None?"}
N -- no --> F
N -- yes --> C["level.append(node.val), q.append(node.left), q.append(node.right) — None children are filtered on the next level"]
C --> F
```
## Solution ## Solution
```py ```py
@@ -59,3 +79,7 @@ class Solution:
return res return res
``` ```
## Explanation
<YouTube id="6ZnyEApgFYg" title="Binary Tree Level Order Traversal - BFS - Leetcode 102" />
@@ -21,6 +21,16 @@ sidebar:
- The number of nodes in the tree is in the range [0, 10^4]. - The number of nodes in the tree is in the range [0, 10^4].
- `-100 <= Node.val <= 100` - `-100 <= Node.val <= 100`
## Approach
```mermaid
flowchart TD
S(["maxDepth(root)"]) --> B{"root is None?"}
B -- yes --> Z(["return 0"])
B -- no --> L["l = maxDepth(root.left), r = maxDepth(root.right)"]
L --> E(["return 1 + max(l, r) — this node adds one level above its deeper subtree"])
```
## Solution ## Solution
```py ```py
@@ -37,3 +47,7 @@ class Solution:
return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right)) return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))
``` ```
## Explanation
<YouTube id="hTM3phVI6YQ" title="Maximum Depth of Binary Tree - 3 Solutions - Leetcode 104 - Python" />
@@ -28,6 +28,22 @@ sidebar:
- The number of nodes in the binary tree is in the range [1, 10^5]. - The number of nodes in the binary tree is in the range [1, 10^5].
- Each node's value is between [-10^4, 10^4]. - Each node's value is between [-10^4, 10^4].
## Approach
```mermaid
flowchart TD
S(["goodNodes(root)"]) --> C["dfs(root, root.val) — the root is always good"]
C --> E(["return that count"])
subgraph dfs["dfs(node, max_val)"]
D1{"node is None?"} -- yes --> D2(["return 0"])
D1 -- no --> D3["is_good = 1 if node.val >= max_val else 0 — max_val is the largest value on the path so far"]
D3 --> D4["new_max = max(max_val, node.val)"]
D4 --> D5["l = dfs(node.left, new_max), r = dfs(node.right, new_max)"]
D5 --> D6(["return is_good + l + r"])
end
C --> dfs
```
## Solution ## Solution
```py ```py
@@ -50,3 +66,7 @@ class Solution:
return dfs(root, root.val) return dfs(root, root.val)
``` ```
## Explanation
<YouTube id="7cp5imvDzl4" title="Microsoft's Most Asked Question 2021 - Count Good Nodes in a Binary Tree - Leetcode 1448 - Python" />
@@ -29,6 +29,26 @@ sidebar:
- The number of nodes in the tree is in the range [0, 100]. - The number of nodes in the tree is in the range [0, 100].
- `-100 <= Node.val <= 100` - `-100 <= Node.val <= 100`
## Approach
```mermaid
flowchart TD
S(["rightSideView(root)"]) --> I["res = [], q = deque([root])"]
I --> W{"q non-empty?"}
W -- no --> E(["return res"])
W -- yes --> L["rightSide = None, qLen = len(q) — qLen freezes the current level's size"]
L --> F{"more i in range(qLen)?"}
F -- no --> V{"rightSide is not None?"}
V -- yes --> A["res.append(rightSide.val) — the last real node popped on this level is the rightmost"]
A --> W
V -- no --> W
F -- yes --> P["node = q.popleft()"]
P --> N{"node is not None?"}
N -- no --> F
N -- yes --> C["rightSide = node, q.append(node.left), q.append(node.right)"]
C --> F
```
## Solution ## Solution
```py ```py
@@ -62,3 +82,7 @@ class Solution:
return res return res
``` ```
## Explanation
<YouTube id="d4zLyf32e3I" title="Binary Tree Right Side View - Breadth First Search - Leetcode 199" />
@@ -25,6 +25,17 @@ sidebar:
- The number of nodes in the tree is in the range [0, 100]. - The number of nodes in the tree is in the range [0, 100].
- `-100 <= Node.val <= 100` - `-100 <= Node.val <= 100`
## Approach
```mermaid
flowchart TD
S(["invertTree(root)"]) --> B{"root is None?"}
B -- yes --> Z(["return None"])
B -- no --> L["left = invertTree(root.left), right = invertTree(root.right) — both subtrees are already inverted"]
L --> X["root.left = right, root.right = left"]
X --> E(["return root"])
```
## Solution ## Solution
```py ```py
@@ -47,3 +58,7 @@ class Solution:
return root return root
``` ```
## Explanation
<YouTube id="OnSn2XEQ4MY" title="Invert Binary Tree - Depth First Search - Leetcode 226" />
@@ -26,6 +26,23 @@ If the BST is modified often (i.e., we can do insert and delete operations) and
- `1 <= k <= n <= 10^4` - `1 <= k <= n <= 10^4`
- `0 <= Node.val <= 10^4` - `0 <= Node.val <= 10^4`
## Approach
```mermaid
flowchart TD
S(["kthSmallest(root, k)"]) --> I["n = 0, stack = [], cur = root"]
I --> W{"cur or stack?"}
W -- no --> E(["fall off the loop — unreachable, k <= n"])
W -- yes --> L{"cur?"}
L -- yes --> P["stack.append(cur), cur = cur.left — push the whole left spine"]
P --> L
L -- no --> O["cur = stack.pop(), n += 1 — nodes pop in ascending order"]
O --> K{"n == k?"}
K -- yes --> R(["return cur.val"])
K -- no --> N["cur = cur.right"]
N --> W
```
## Solution ## Solution
```py ```py
@@ -52,3 +69,7 @@ class Solution:
return cur.val return cur.val
cur = cur.right cur = cur.right
``` ```
## Explanation
<YouTube id="5LUXSvjmGCw" title="Kth Smallest Element in a BST - Leetcode 230 - Python" />
@@ -30,6 +30,22 @@ sidebar:
- `p != q` - `p != q`
- p and q will exist in the BST. - p and q will exist in the BST.
## Approach
```mermaid
flowchart TD
S(["lowestCommonAncestor(root, p, q)"]) --> I["cur = root"]
I --> W{"cur?"}
W -- no --> E(["fall off the loop — unreachable, p and q exist in the BST"])
W -- yes --> A{"p.val < cur.val and q.val < cur.val?"}
A -- yes --> L["cur = cur.left — both sit in the left subtree"]
L --> W
A -- no --> B{"p.val > cur.val and q.val > cur.val?"}
B -- yes --> R["cur = cur.right — both sit in the right subtree"]
R --> W
B -- no --> C(["return cur — the paths to p and q split here"])
```
## Solution ## Solution
```py ```py
@@ -54,3 +70,7 @@ class Solution:
else: else:
return cur return cur
``` ```
## Explanation
<YouTube id="gs2LMfuOR9k" title="Lowest Common Ancestor of a Binary Search Tree - Leetcode 235 - Python" />
@@ -30,6 +30,21 @@ sidebar:
- `p != q` - `p != q`
- p and q will exist in the tree. - p and q will exist in the tree.
## Approach
```mermaid
flowchart TD
S(["lowestCommonAncestor(root, p, q)"]) --> B{"not root?"}
B -- yes --> N(["return None"])
B -- no --> M{"root == p or root == q?"}
M -- yes --> R(["return root — a node is its own ancestor"])
M -- no --> L["l = self.lowestCommonAncestor(root.left, p, q)"]
L --> Q["r = self.lowestCommonAncestor(root.right, p, q)"]
Q --> D{"l and r?"}
D -- yes --> A(["return root — p and q were found on different sides"])
D -- no --> E(["return l or r — pass up whichever side found something"])
```
## Solution ## Solution
```py ```py
@@ -22,6 +22,23 @@ sidebar:
- The number of nodes in the tree is in the range [1, 10^4]. - The number of nodes in the tree is in the range [1, 10^4].
- `-2^31 <= Node.val <= 2^31 - 1` - `-2^31 <= Node.val <= 2^31 - 1`
## Approach
```mermaid
flowchart TD
S(["isValidBST(root)"]) --> C["valid(root, float('-inf'), float('inf')) — the root may hold any value"]
C --> E(["return that result"])
subgraph valid["valid(node, low, high)"]
V1{"not node?"}
V1 -- yes --> V2(["return True"])
V1 -- no --> V3{"not (low < node.val < high)?"}
V3 -- yes --> V4(["return False — node breaks a bound set by an ancestor"])
V3 -- no --> V5["valid(node.left, low, node.val) and valid(node.right, node.val, high) — each child tightens one bound"]
V5 --> V6(["return that result"])
end
C --> V1
```
## Solution ## Solution
```py ```py
@@ -44,3 +61,7 @@ class Solution:
return valid(root, float("-inf"), float("inf")) return valid(root, float("-inf"), float("inf"))
``` ```
## Explanation
<YouTube id="s6ATEkipzow" title="Validate Binary Search Tree - Depth First Search - Leetcode 98" />