Skip to content

Commit b2543d1

Browse files
committed
Update notes and problem solutions
1 parent f3ee0f8 commit b2543d1

File tree

58 files changed

+979
-356
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+979
-356
lines changed

leetcode/100.same-tree.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ Output: True
1818
```
1919
### Edge / Corner Cases
2020
* Values are the same, but different structurely.
21-
```
21+
```js
2222
Input:
2323
1
2424
/
2525
2
26+
27+
// Or
2628
1
2729
\
2830
2
@@ -50,8 +52,8 @@ fun isSameTree(p: TreeNode?, q: TreeNode?): Boolean {
5052
}
5153
```
5254

53-
* **Time Complexity**: `O(min(P, Q))`, where `P` and `Q` are the number of tree nodes of `p` and `q`.
54-
* **Space Complexity**: `O(min(P, Q))`
55+
* **Time Complexity**: `O(min(P, Q))`, where `P` and `Q` are the number of tree nodes of `p` and `q`, we terminate the recursion when we reach the end of the smaller tree.
56+
* **Space Complexity**: `O(min(Hp, Hq))`, where `Hp` and `Hq` are the height of the tree of `p` and `q`.
5557

5658
## Iterative
5759
```kotlin

leetcode/101.symmetric-tree.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,22 @@ fun isSymmetric(root: TreeNode?): Boolean {
7979
}
8080
```
8181
* **Time Complexity**: `O(n)`, where `n` is the number of tree nodes.
82-
* **Space Complexity**: `O(n)`, where `n` is the number of tree nodes.
82+
* **Space Complexity**: `O(n)`, where `n` is the number of tree nodes.
83+
84+
## Symmetric 3-ary Tree
85+
```kotlin
86+
fun isSymmetric(root: TreeNode?): Boolean {
87+
if (root == null) return true
88+
return check(root.left, root.right) && isSymmetric(root.center)
89+
}
90+
91+
private fun check(left: TreeNode?, right: TreeNode?): Boolean {
92+
if (left == null && right == null) return true
93+
if (left == null || right == null) return false
94+
return (left.`val` == right.`val`) &&
95+
check(left.left, right.right) &&
96+
check(left.right, right.left) &&
97+
isSymmetric(left.center) &&
98+
isSymmetric(right.center)
99+
}
100+
```
Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,100 @@
1-
#[1011. Capacity To Ship Packages Within D Days](https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/)
1+
# [1011. Capacity To Ship Packages Within D Days](https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/)
2+
3+
## Linear Search
4+
We can start linear search by iterating the capacity from 1 and find the first capacity that can ship all packages within `days`.
5+
6+
```js
7+
days = 3
8+
capacity 1, 2, 3, 4, 5 day
9+
10+
1 [1, 2, 3, 4, 5] = 15 X
11+
2 [1, 1, 2, 2, 3] = 9 X
12+
3 [ 1, 1, 2, 2] = 6 X
13+
4 [ 1, 1, 1, 2] = 5 X
14+
5 [ 1, 1, 1, 1] = 4 X
15+
6 [ 1, 1, 1] = 3 O <- the least weight capacity
16+
17+
...
18+
10 [ 1, 1] = 2 O
19+
20+
...
21+
15 [ 1] = 1 O
22+
```
23+
24+
## Binary Search
25+
But we can optimize the solution with some key observations:
26+
27+
The intuition is that without considering the limiting days `D`, we can ship all packages in one day with the maximum weight.
28+
29+
```js
30+
[1, 2, 3, 4, 5], max = 5
31+
32+
=> [1, 2] [3] [4] [5]
33+
```
34+
35+
To ship exactly `D` days and minimize the max sum of any partition, we're looking for the minimal one among all feasible capacities. If we can ship all packages within `D` days, then we can definitely ship them with a larger capacity. If we can't ship all packages within `D` days, then we can't ship them with a smaller capacity.
36+
37+
1. The minimum capacity is the maximum of the weights, because we can't ship the package with the capacity less than the maximum weight.
38+
2. The maximum capacity is the sum of the weights because we can ship all packages in one day.
39+
3. As we increase the capacity, the shipped days decreases, and vice versa. This exhibits the **monotonicity** characteristic, so we can use binary search to find the minimum capacity: **We're looking for the first element that satisfies the condition: `shipDays(weights, middle) <= days`**.
40+
41+
For `shipDays(weights, capacity)`, we can calculate the days needed to ship all packages with the given capacity. We iterate the weights and accumulate the weight greedily before it exceeds the capacity. If it exceeds the capacity, we increment the days and reset the load to the current weight.
42+
43+
```kotlin
44+
class Solution {
45+
fun shipWithinDays(weights: IntArray, days: Int): Int {
46+
var max = Int.MIN_VALUE
47+
var sum = 0
48+
for (w in weights) {
49+
max = maxOf(max, w)
50+
sum += w
51+
}
52+
53+
var left = max
54+
var right = sum
55+
while (left <= right) {
56+
val middle = left + (right - left) / 2
57+
val canShipped = shippedDays(weights, middle) <= days
58+
// capacity
59+
// X X X O O O O O
60+
if (canShipped) {
61+
right = middle - 1
62+
} else {
63+
left = middle + 1
64+
}
65+
}
66+
return left
67+
}
68+
}
69+
70+
private fun getShipDays(weights: IntArray, capacity: Int): Int {
71+
var days = 1
72+
var load = 0
73+
// in the order given by weights as problem description
74+
for (w in weights) {
75+
if (load + w > capacity) {
76+
days++
77+
load = 0
78+
}
79+
load += w
80+
}
81+
return days
82+
}
83+
84+
// or equivalently
85+
private fun getShipDays(weights: IntArray, capacity: Int): Int {
86+
var days = 1
87+
var load = 0
88+
for (w in weights) {
89+
load += w
90+
if (load > capacity) {
91+
days++
92+
load = w
93+
}
94+
}
95+
return days
96+
}
97+
```
98+
99+
* **Time Complexity:** `O(n log m)`, where `n` is the number of weights and `m` is the sum of the weights.
100+
* **Space Complexity:** `O(1)`.

leetcode/103.binary-tree-zigzag-level-order-traversal.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,7 @@ fun zigzagLevelOrder(root: TreeNode?): List<List<Int>> {
4747

4848
return results
4949
}
50-
```
50+
```
51+
52+
* **Time Complexity**: `O(n)`
53+
* **Space Complexity**: `O(n)`

leetcode/1038.binary-search-tree-to-greater-sum-tree.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,10 @@ private fun build(root: TreeNode?, value: Int): Int {
7878
// Root 4 will receive 19, not 14. Because 21 is the sum of 5, 6, 8.
7979
return currentSum
8080
}
81+
```
8182

82-
// Or equivalently, we can maintain a global variable to store the sum.
83+
Or equivalently, we can maintain a global variable to store the sum.
84+
```kotlin
8385
private var sum = 0
8486
fun bstToGst(root: TreeNode?): TreeNode? {
8587
inorder(root)

leetcode/104.maximum-depth-of-binary-tree.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ fun maxDepth(root: TreeNode?): Int {
4343
```
4444

4545
* **Time Complexity**: `O(n)`, we traverse all nodes once.
46-
* **Space Complextiy**: `O(H)`, recursion need space for stack, and the space depends on the height of the tree. The height might be `lg n` (balanced) or `n` (skewed)
46+
* **Space Complextiy**: `O(h)`, recursion need space for stack, and the space depends on the height of the tree. The height might be `lg n` (balanced) or `n` (skewed)
4747

4848
### BFS
4949
```kotlin
@@ -65,4 +65,4 @@ fun maxDepth(root: TreeNode?): Int {
6565
}
6666
```
6767
* **Time Complexity**: `O(n)`, we traverse all nodes once.
68-
* **Space Complexity**: `O(n)`, we traverse all nodes in queue.
68+
* **Space Complexity**: `O(n)`, we enqueue all nodes in the queue.

leetcode/111.minimum-depth-of-binary-tree.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ fun minDepth(root: TreeNode?): Int {
9191
}
9292
```
9393
* **Time Complexity**: `O(n)`, iterate all nodes.
94-
* **Space Complexity**: `O(n)`, the worst case is the tree is a linked list, so the recursion stack will store all nodes.
94+
* **Space Complexity**: `O(h)`, the worst case is the tree is a linked list, so the recursion stack will store all nodes, which is `O(n)`.
9595

9696
## BFS
9797
We traversal level by level, and search the first leaf node, then return the depth.

leetcode/114.flatten-binary-tree-to-linked-list.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ private fun subtreeLast(root: TreeNode): TreeNode {
150150
## Preorder with Pointers (Space Optimization)
151151
Idea is the same, but we traversal with pointers only (removing stack or recursion).
152152

153+
> Nice illustration: https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/solutions/356853/er-cha-shu-zhan-kai-wei-lian-biao-by-leetcode-solu/
154+
153155
```kotlin
154156
fun flatten(root: TreeNode?): Unit {
155157
if (root == null) return

leetcode/116.populating-next-right-pointers-in-each-node.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ Input:
1616
Output:
1717
1 -> null
1818
/ \
19-
2 -> 3 -> null
19+
2 --> 3 -> null
2020
/ \ / \
21-
4-> 5 6-> 7 -> null
21+
4-> 5>6-> 7 -> null
2222
```
2323
### Edge / Corner Cases
2424
* Empty or single node tree

leetcode/1254.number-of-closed-islands.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,7 @@ class Solution {
136136
}
137137
}
138138
}
139-
```
139+
```
140+
141+
* **Time Complexity**: `O(m * n)`.
142+
* **Space Complexity**: `O(m * n)`.

leetcode/1315.sum-of-nodes-with-even-valued-grandparent.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,7 @@ private fun dfs(root: TreeNode?, parent: TreeNode?, grandparent: TreeNode?) {
101101
dfs(root.left, root, parent)
102102
dfs(root.right, root, parent)
103103
}
104-
```
104+
```
105+
106+
* **Time Complexity**: `O(n)`.
107+
* **Space Complexity**: `O(n)`.

leetcode/133.clone-graph.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ private fun clone(node: Node?): Node? {
6262
val newNode = Node(node.`val`)
6363
oldNewMapping[node] = newNode
6464
node.neighbors.forEach { adj ->
65+
// Clone the neighbors during the DFS traversal recursively.
6566
newNode.neighbors.add(clone(adj))
6667
}
6768
return newNode

leetcode/1870.minimum-speed-to-arrive-on-time.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ fun minSpeedOnTime(dist: IntArray, hour: Double): Int {
3232

3333
## Binary Search
3434
We can optimize the linear search solution with some modifications based on some key observations:
35-
1. The minimum speed is `1`, and the maximum speed is the maximum of possible value, which is `10^7`.
35+
1. The minimum speed is `1`, and the maximum speed is the maximum of possible value, which is `10^7` (based on the problem constraints).
3636
2. As we increase the speed, the time to reach the office is shorter, and vice versa. This exhibits the **monotonicity** characteristic, so we can use binary search to find the minimum speed: **We're looking for the first element that satisfies the condition: `getTotalHours(dist, middle) <= hour`**.
3737

38+
> It's a little bit confused why we don't ceil the last distance, maybe just skip it.
39+
3840
```kotlin
3941
fun minSpeedOnTime(dist: IntArray, hour: Double): Int {
4042
val min = 1
@@ -55,6 +57,8 @@ fun minSpeedOnTime(dist: IntArray, hour: Double): Int {
5557
}
5658
// We check if the left is in the range, if not, return -1
5759
return if (left in min..max) left else -1
60+
// Or
61+
// return if (left > max) -1 else left
5862
}
5963

6064
// We calculate the total hours to reach the office with the given speed.

leetcode/2115.find-all-possible-recipes-from-given-supplies.md

Lines changed: 7 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -18,36 +18,24 @@ Output:
1818

1919
Suppose we the following recipes, ingredients and supplies:
2020
```js
21-
Recipes = [R2, R1]
22-
Ingredients = [[C, R1, D, B], [A, B]]
23-
Supplies = [A, B, C, D]
21+
Recipes = [C, D]
22+
Ingredients = [[A, B], [B, C]]
23+
Supplies = [A, B]
2424
```
2525

2626
For each recipe `recipes[i]`, we have the `ingredients[i]` that can make it, we take them as edges from ingredient to recipe:
2727

2828
```js
2929
// Graph (visualization)
30-
C, R1, D, B => R2
31-
A, B => R1
30+
A, B => C
31+
B, C => D
3232
```
3333

3434
And we can use topological sort to find out what recipes can be made from our ingredients, supplies and even recipes we just have made it.
3535

3636
So we build the graph from ingredients and count the indegrees for every recipes, and run BFS.
37-
```js
38-
// Graph (data structure)
39-
C: [R2]
40-
R1:[R2]
41-
D: [R2]
42-
B: [R2, R1]
43-
A: [R1]
44-
45-
// Indegrees:
46-
R2: 4
47-
R1: 2
48-
```
4937

50-
### Topological Sort (BFS)
38+
## Topological Sort (BFS)
5139
```kotlin
5240
fun findAllRecipes(recipes: Array<String>, ingredients: List<List<String>>, supplies: Array<String>): List<String> {
5341
val graph = hashMapOf<String, HashSet<String>>()
@@ -85,68 +73,4 @@ fun findAllRecipes(recipes: Array<String>, ingredients: List<List<String>>, supp
8573
```
8674

8775
* **Time Complexity**: `O(R*I + S + R)` = `O(R*I + S)` where `R`, `I`, `S` represent the number of recipes, ingredients and supplies.
88-
* **Space Complexity**: `O(R*I + S)` for graph and queue.
89-
90-
### ~~Brute Force~~
91-
```kotlin
92-
fun findAllRecipes(recipes: Array<String>, ingredients: List<List<String>>, supplies: Array<String>): List<String> {
93-
94-
val finishedRecipes = hashSetOf<String>()
95-
val suppliesSet = hashSetOf<String>()
96-
for (s in supplies) { suppliesSet.add(s) }
97-
98-
var recipeIndex = 0
99-
while (recipeIndex < recipes.size) {
100-
if (finishedRecipes.contains(recipes[recipeIndex])) {
101-
recipeIndex++
102-
continue
103-
}
104-
val ingredient = ingredients[recipeIndex]
105-
var canMake = true
106-
for (i in 0 until ingredient.size) {
107-
if (!suppliesSet.contains(ingredient[i]) && !finishedRecipes.contains(ingredient[i])) {
108-
canMake = false
109-
break
110-
}
111-
}
112-
113-
if (canMake) {
114-
finishedRecipes.add(recipes[recipeIndex])
115-
recipeIndex = 0
116-
} else {
117-
recipeIndex++
118-
}
119-
}
120-
return ArrayList<String>(finishedRecipes)
121-
}
122-
```
123-
124-
* **Time Complexity**: `O(S + R^2 * I)`, where `R`, `I` and `S` represents the number of recipes, the max length in `ingredient[i]`, and the number of supplies.
125-
* **Space Complexity**: `O(R + S)`.
126-
127-
128-
```js
129-
// Recipes = [R2, R1]
130-
// Ingredients = [[C, R1, D, B], [A, B]]
131-
// Supplies = [A, B, C, D]
132-
133-
// Graph (visualization)
134-
// C, R1, D, B => R2
135-
// A, B => R1
136-
137-
// Graph (data structure)
138-
C: [R2]
139-
R1:[R2]
140-
D: [R2]
141-
B: [R2, R1]
142-
A: [R1]
143-
144-
// Indegrees:
145-
R2: 0
146-
R1: 0
147-
148-
Queue: , , , , R2
149-
Current: R2
150-
151-
Results: R1, R2
152-
```
76+
* **Space Complexity**: `O(R*I + S)` for graph and queue.

0 commit comments

Comments
 (0)