Skip to content

Commit e55d623

Browse files
committed
Update the explanation videos or references to problem listings
1 parent 1effb0c commit e55d623

13 files changed

+187
-83
lines changed

leetcode/112.path-sum.md

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
# [112. Path Sum](https://leetcode.com/problems/path-sum/)
22

3-
## Clarification Questions
4-
* No, it's clear from problem description.
5-
63
## Test Cases
74
### Normal Cases
85
```
@@ -46,27 +43,15 @@ fun hasPathSum(root: TreeNode?, targetSum: Int): Boolean {
4643

4744
private fun pathSum(root: TreeNode?, sum: Int, target: Int): Boolean {
4845
if (root == null) return false
49-
if (root.left == null && root.right == null) {
50-
return sum + root.`val` == target
51-
}
52-
53-
return pathSum(root.left, sum + root.`val`, target) ||
54-
pathSum(root.right, sum + root.`val`, target)
55-
}
56-
57-
// root: The current node we are processing now
58-
// currentSum: The sum before processing the current node
59-
private fun dfs(root: TreeNode?, sum: Int) {
60-
if (root == null) return
61-
6246
// Process current node
6347
val currentSum = sum + root.`val`
6448

65-
// Do something with the current node
49+
if (root.left == null && root.right == null) {
50+
return curretnSum == target
51+
}
6652

67-
// Child nodes
68-
dfs(root.left, currentSum)
69-
dfs(root.right, currentSum)
53+
return pathSum(root.left, currentSum, target) ||
54+
pathSum(root.right, currentSum, target)
7055
}
7156
```
7257

leetcode/1339.maximum-product-of-splitted-binary-tree.md

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,44 @@
33
## Postorder
44
For a root node, how can we split into two subtrees to get the product of the sums of the subtrees?
55
```js
6-
2
7-
/ \
8-
3 4
6+
10
7+
/ \
8+
3 4
99

1010
// Can split into two cases
11-
2 2
12-
\ or /
13-
3 4 3 4
14-
15-
= 3 * 6 or 5 * 4
11+
10 10
12+
\ or /
13+
X 4 3 X
14+
15+
= 3 * 14 or 13 * 4
1616
```
17-
If we split the left child, for example, then the product will be `3 * (2 + 4)`, which is `the sum of the left subtree` x `total sum - the left subtree`. (The same for the right child)
17+
If we split the left child, for example, then the product will be `3 * (10 + 4)`, which is `the sum of the left subtree` x `total sum - the left subtree`. (The same for the right child)
1818

1919
So for any root node, we can calculate the left subtree sum and the right subtree sum, and then
2020
* Split left = `sum(left) * (total sum - sum(left))`
2121
```js
22-
root
22+
root
2323
\
2424
sum(left) sum(right)
2525
```
2626
* Split right = `(total sum - sum(right)) * sum(right)`
2727
```js
28-
root
28+
root
2929
/
3030
sum(left) sum(right)
3131
```
3232

33-
We can use postorder to calculate the sum of the subtree and the total sum of the tree. Then we can calculate the product of the splitted tree for each node and update the maximum product.
33+
We compute the total sum of the tree first, then use postorder to compute subtree sums and update the maximum product while computing the sum of the tree.
3434

3535
```kotlin
36-
private val mod = 1000000000L + 7
37-
private var result = 0L
36+
private val mod = 10_000_000_007
37+
private var maxProduct = 0L
3838
private var total = 0L
3939

4040
fun maxProduct(root: TreeNode?): Int {
4141
total = sum(root)
4242
sum(root)
43-
return (result % mod).toInt()
43+
return (maxProduct % mod).toInt()
4444
}
4545

4646
private fun sum(root: TreeNode?): Long {
@@ -54,37 +54,34 @@ private fun sum(root: TreeNode?): Long {
5454

5555
val leftSplit = left * (total - left) // 2 * (10 - 2)
5656
val rightSplit = (total - right) * right // (10 - 3) * 3
57-
result = maxOf(result, maxOf(leftSplit, rightSplit))
57+
maxProduct = maxOf(maxProduct, maxOf(leftSplit, rightSplit))
5858

59-
return root.`val`.toLong()+ left + right
59+
return root.`val`.toLong() + left + right
6060
}
6161
```
6262

6363
Or the same idea, we can split at root node:
6464
```js
6565
parent
6666
\
67-
X // split here
67+
X // split here when calculating the sum of `root`
6868
\
6969
root sum(root)
7070
/ \
7171
left right
72+
```
7273

7374
```kotlin
74-
private val mod = 1000000000L + 7
75-
private var result = 0L
76-
private var total = 0L
77-
7875
fun maxProduct(root: TreeNode?): Int {
7976
total = sum(root)
8077
sum(root)
81-
return (result % mod).toInt()
78+
return (maxProduct % mod).toInt()
8279
}
8380

8481
private fun sum(root: TreeNode?): Long {
8582
if (root == null) return 0L
8683
val currentSum = root.`val` + sum(root.left) + sum(root.right)
87-
result = maxOf(result, currentSum * (total - currentSum))
84+
maxProduct = maxOf(maxProduct, currentSum * (total - currentSum))
8885
return currentSum
8986
}
9087
```

leetcode/1552.magnetic-force-between-two-balls.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ positions: a, _, _, d, _, _, _, e, _ f
1111
|----| // The minimum distance
1212
```
1313

14-
We have a fixed search range, next, we'd like to discover the monotonicity characteristic to apply binary search:
14+
We have a fixed search space, next, we'd like to discover the monotonicity characteristic to apply binary search:
1515

1616
**As the distance increases, the number of balls we can place decreases. (we have to put `m` balls)**
1717
* If we can place all the balls with a minimum distance `d` (other distances might be larger than `d`, it's acceptable), then we can also place all the balls with a shorter distance `d2` where `d2 < d`. For example, we can put 3 balls with the distance `4`, then we can also put 3 balls with the distance `3`, `2`, `1`.

leetcode/2064.minimized-maximum-of-products-distributed-to-any-store.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ quantities = [1]
4444
[1],[0], ... , [0], ... ,[0]
4545
```
4646

47-
This forms a **fixed search range** for the answer, `[1, max(quantities)]`:
47+
This forms a **fixed search space** for the answer, `[1, max(quantities)]`:
4848
* Lower bound is `1`, we must distribute at least one product to stores. (Some stores may get `0` products if there is not enough products to distribute)
4949
* Upper bound is the `max(quantities)`, because we can distribute all products of single type to one store.
5050

leetcode/410.split-array-largest-sum.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ We try to minimize the largest sum amoung `k` subarrays:
1717
* Upper bound is `sum(nums)`, because we can split the array into `k == 1` subarray (only one split) which is `[7 + 2 + 5 + 10 + 8]` = `32`.
1818
The possible answer must be in the range `[max(nums), sum(nums)]`.
1919

20-
Since we have a fixed search range, then we have to discover the monotonicity characteristic to apply binary search:
20+
Since we have a fixed search space, then we have to discover the monotonicity characteristic to apply binary search:
2121
* Given a largest sum `ans` (answer), if we can split the array into `k` groups, then we also can split the array with larger value `ans + 1`, `ans + 2`, etc. Because there are more numbers formed one split with the larger value, the total split count will become less, which also satisfy the condition: `splitCount <= k`. (Why `splitCount < k` is also acceptable? See below)
2222
* If the largest sum is too small that we can't split the array into `k` groups (more than `k` splits), then we also can't split the array with smaller largest sum since smaller value will have more splits.
2323

leetcode/563.binary-tree-tilt.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# [563. Binary Tree Tilt](https://leetcode.com/problems/binary-tree-tilt/description/)
22

3+
## Breakdowns
4+
* The tilt of a node is `abs(sum(left) - sum(right))`.
5+
* The answer is the tilt of the whole tree, which is the sum of the tilt of all nodes.
6+
37
## Top-Down Approach (Double Recursion)
4-
For each node, we have to calculate the left and right sum to calculate current tilt. Then we calculate the tilt of left and right child. The tilt of left and right child is the same problem, so we can use recursion to solve it.
8+
For each node, we have to calculate the left and right sum to calculate current tilt. Then we calculate the sum of the tilt of current + left + right.
59

610
```kotlin
711
fun findTilt(root: TreeNode?): Int {
@@ -26,7 +30,7 @@ private fun sum(root: TreeNode?): Int {
2630
* **Space Complexity:** `O(n)`
2731

2832
## Bottom-Up Approach (Single Recursion)
29-
We can update the global result during calculating the sum of the tree. We can return the sum of the current root and update the global result.
33+
We can optimize the top-down approach by calculating the sum of the tree and tilt at the same time in bottom-up approach. At each node, we return the sum of the tree to its parent, and maintain a global variable to track the tilt sum.
3034

3135
```kotlin
3236
private var tiltSum = 0
@@ -48,5 +52,25 @@ private fun sum(root: TreeNode?): Int {
4852
}
4953
```
5054

55+
Or equivalently, we return sum of tilt and sum of the tree in a pair.
56+
57+
```kotlin
58+
fun findTilt(root: TreeNode?): Int {
59+
return sum(root).first
60+
}
61+
62+
// return <sum of tilt, sum of subtree>
63+
private fun sum(root: TreeNode?): Pair<Int, Int> {
64+
if (root == null) return 0 to 0
65+
val left = sum(root.left)
66+
val right = sum(root.right)
67+
68+
val tilt = abs(left.second - right.second)
69+
val nodeSum = root.`val` + left.second + right.second
70+
val tiltSum = tilt + left.first + right.first
71+
return tiltSum to nodeSum
72+
}
73+
```
74+
5175
* **Time Complexity:** `O(n)`
5276
* **Space Complexity:** `O(n)`

leetcode/671.second-minimum-node-in-a-binary-tree.md

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
# [671. Second Minimum Node In a Binary Tree](https://leetcode.com/problems/second-minimum-node-in-a-binary-tree/description/)
22

3-
# Test Cases
4-
### Normal Cases
5-
```
6-
Input:
7-
Output:
8-
```
3+
## Test Cases
94
### Edge / Corner Cases
105
* All the values are the same.
116
```
@@ -30,40 +25,92 @@ Output: 2
3025
```
3126

3227
## DFS
28+
We can traverse the tree and find the second minimum value directly.
29+
30+
```kotlin
31+
private var min1 = Long.MAX_VALUE
32+
private var min2 = Long.MAX_VALUE
33+
34+
fun findSecondMinimumValue(root: TreeNode?): Int {
35+
dfs(root)
36+
return if (min2 == Long.MAX_VALUE) -1 else min2.toInt()
37+
}
38+
39+
private fun dfs(root: TreeNode?) {
40+
if (root == null) return
41+
val value = root.`val`.toLong()
42+
if (value < min1) {
43+
min2 = min1
44+
min1 = value
45+
} else if (min1 < value && value < min2) {
46+
min2 = value
47+
}
48+
dfs(root.left)
49+
dfs(root.right)
50+
}
51+
```
52+
53+
The straightforward solution is not using the special property of the tree. We can optimize the solution by using the property of the tree.
54+
3355
Based on the special property of the tree:
3456
* The top-level root is the first minimum value.
3557
* The value of root node <= the value of its children nodes.
3658

37-
We find the value that is greater than the top-level root value but smaller than any existing value.
59+
We find the value that is **greater than the top-level root value but minimum value among nodes**.
3860

3961
> 我们只需要通过遍历,找出严格大于 rootvalue 的最小值,即为「所有节点中的第二小的值」。
4062
4163
```kotlin;
42-
private var firstMin = Long.MAX_VALUE
43-
private var secondMin = Long.MAX_VALUE
64+
private var min1 = Long.MAX_VALUE
65+
private var min2 = Long.MAX_VALUE
4466
4567
fun findSecondMinimumValue(root: TreeNode?): Int {
4668
if (root == null) return -1
4769
// The top-level root is the first minimum value.
48-
firstMin = root.`val`.toLong()
70+
min1 = root.`val`.toLong()
4971
dfs(root)
50-
return if (secondMin == Long.MAX_VALUE) -1 else secondMin.toInt()
72+
return if (min2 == Long.MAX_VALUE) -1 else min2.toInt()
5173
}
5274
75+
// Find the mimimum value that is greater than the root value. (not the 2nd minimum value)
5376
private fun dfs(root: TreeNode?) {
5477
if (root == null) return
5578
val rootValue = root.`val`.toLong()
56-
// root value <= children values, so we don't need to check the children values.
57-
if (secondMin < rootValue) return
79+
// (Optional) if root value <= children values, so we don't need to check the children values.
80+
// The children are impossible to be the minimum value.
81+
if (min2 <= rootValue) return
5882
59-
// Update the second minimum value.
60-
if (firstMin < rootValue && rootValue < secondMin) {
61-
secondMin = rootValue
83+
// If it's the minimum value that is greater than the root value.
84+
if (min1 < rootValue && rootValue < min2) {
85+
min2 = rootValue
6286
}
6387
dfs(root.left)
6488
dfs(root.right)
6589
}
6690
```
6791

92+
Or equivalently, we can return the minimum value that is greater than the root value from `dfs()` function:
93+
```kotlin
94+
fun findSecondMinimumValue(root: TreeNode?): Int {
95+
if (root == null) return -1
96+
val min2 = dfs(root, root.`val`.toLong())
97+
return if (min2 == Long.MAX_VALUE) -1 else min2.toInt()
98+
}
99+
100+
private fun dfs(root: TreeNode?, min1: Long): Long {
101+
if (root == null) return Long.MAX_VALUE
102+
103+
val rootValue = root.`val`.toLong()
104+
if (min1 < rootValue) {
105+
return rootValue
106+
}
107+
val left = dfs(root.left, min1)
108+
val right = dfs(root.right, min1)
109+
if (left == Long.MAX_VALUE) return right
110+
if (right == Long.MAX_VALUE) return left
111+
return minOf(left, right)
112+
}
113+
```
114+
68115
* **Time Complexity:** `O(n)`
69116
* **Space Complexity:** `O(h)`

leetcode/875.koko-eating-bananas.md

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,6 @@
55
* `h` range?
66
* What is the range of `piles[i]`? Will it be negative?
77

8-
## Test Cases
9-
### Normal Cases
10-
```
11-
Input:
12-
Output:
13-
```
14-
### Edge / Corner Cases
15-
*
16-
```
17-
Input:
18-
Output:
19-
```
20-
218
## Linear Search
229
We're finding the speed slow enough and can eat all within `n` hours. Let's start from eating 1 banana per hour, and check if it's possible to eat all piles within `h` hours. If not, we increase the speed by 1 and check again.
2310

@@ -33,6 +20,8 @@ fun minEatingSpeed(piles: IntArray, h: Int): Int {
3320

3421
## Binary Search
3522
We can optimize the linear search solution with some modifications based on some key observations:
23+
24+
### Search Space
3625
1. Every time Koko eats at least one banana, so the minimum speed is 1.
3726
2. The maximum speed is the maximum of piles because Koko chooses only one pile to eat at a time.
3827
3. As the eating speed is slower, the required hours is longer, and vice versa. And if we can find the minimum speed to eat all, then any higher speed would be eat all as well. And if we can't find the minimum speed to eat all, then any lower speed would be impossible to eat all. This exhibits the **monotonicity** characteristic, so we can use binary search to find the minimum speed: **We're looking for the first (minimal) speed that satisfies the condition: `canEatAll(piles, middle, h)`**.

problems/binary-search-problems.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,25 @@
9393
> * https://leetcode.com/problems/search-in-rotated-sorted-array-ii/ 8k m
9494
> * https://leetcode.com/problems/peak-index-in-a-mountain-array/description/ m
9595
> * https://leetcode.com/problems/kth-missing-positive-number/description/ e
96-
> * **https://leetcode.com/problems/median-of-two-sorted-arrays/description/**
96+
> * **https://leetcode.com/problems/median-of-two-sorted-arrays/description/**
97+
98+
## Explanation
99+
* [34. Find First and Last Position of Element in Sorted Array](https://www.youtube.com/watch?v=sX5IbSSNKXI)
100+
* [475. Heaters](https://www.youtube.com/watch?v=25LSSsAGLDw)
101+
* [875. Koko Eating Bananas](https://www.youtube.com/watch?v=yfWVWbi9pts)
102+
* [1011. Capacity To Ship Packages Within D Days](https://www.youtube.com/watch?v=-F2ysRiSTvk)
103+
* [1482. Minimum Number of Days to Make m Bouquets](https://www.youtube.com/watch?v=D_Pq9SqEwsc)
104+
* [1631. Path With Minimum Effort](https://www.youtube.com/watch?v=vIJ8ue4pQtw)
105+
* [2560. House Robber IV](https://www.youtube.com/watch?v=_-nBUCSeU98)
106+
* [2226. Maximum Candies Allocated to K Children](https://www.youtube.com/watch?v=TBTvnyMLgng)
107+
* [410. Split Array Largest Sum](https://www.youtube.com/watch?v=PBvgA3sV5Zs)
108+
* [2064. Minimized Maximum of Products Distributed to Any Store](https://www.youtube.com/watch?v=0Lyu_B_Ao7k)
109+
* [1552. Magnetic Force Between Two Balls](https://www.youtube.com/watch?v=6oSU44kkV-U)
110+
* [240. Search a 2D Matrix II](https://www.youtube.com/watch?v=-IzCjqVsjZw)
111+
* [378. Kth Smallest Element in a Sorted Matrix](https://www.youtube.com/watch?v=JJUv4DDLSB4)
112+
* [729. My Calendar I](https://www.youtube.com/watch?v=g30lRE3ASiA)
113+
* [1146. Snapshot Array](https://github.com/wisdompeak/LeetCode/tree/master/Design/1146.Snapshot-Array)
114+
* [162. Find Peak Element](https://www.youtube.com/watch?v=esY2RWhmZ74)
115+
* [287. Find the Duplicate Number](https://www.youtube.com/watch?v=86co28GuZ5U)
116+
* [33. Search in Rotated Sorted Array](https://github.com/wisdompeak/LeetCode/tree/master/Binary_Search/033.Search-in-Rotated-Sorted-Array)
117+
* [153. Find Minimum in Rotated Sorted Array](https://github.com/wisdompeak/LeetCode/tree/master/Binary_Search/153.Find-Minimum-in-Rotated-Sorted-Array)

0 commit comments

Comments
 (0)