Skip to content

Commit d08e148

Browse files
committed
Update some notes of different problems
1 parent 02d29a2 commit d08e148

9 files changed

+118
-84
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@ This project offers a curated collection of notes and resources covering fundame
77
- [Introduction](./topics/introduction.md)
88
- [Complexity](./topics/complexity.md)
99
- [Array & String](./topics/array.md)
10-
- [Hash Table](./topics/hash-table.md)
1110
- [Sorting](./topics/sorting.md)
11+
- [Hash Table](./topics/hash-table.md)
1212
- [Binary Search](./topics/binary-search.md)
1313
- [Linked List](./topics/linked-list.md)
1414
- [Stack & Queue](./topics/stack-queue.md)
1515
- [Tree](./topics/tree.md)
1616
- [Heap & Priority Queue](./topics/heap.md)
1717
- [Graph](./topics/graph.md)
18-
- [Shortest Path](./topics/shortest-path.md)
1918
- [Recursion](./topics/recursion.md)
2019
- [Dynamic Programming](./topics/dynamic-programming.md)
2120
- [Greedy](./topics/greedy.md)
21+
- [Shortest Path](./topics/shortest-path.md)
2222
- [Backtracking](./topics/backtracking.md)
2323

2424
## Problems & Solutions

leetcode/1642.furthest-building-you-can-reach.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,4 @@ fun furthestBuilding(heights: IntArray, bricks: Int, ladders: Int): Int {
7777
```
7878

7979
* **Time Complexity**: `O(n lg k)`, `k` is the number of ladders.
80-
* **Space Complexity**: `O(lg k)`
80+
* **Space Complexity**: `O(k)`

leetcode/198.house-robber.md

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,6 @@
22

33
For the house of `i` we have two choises: robber the `i-2` and `i` house or robber `i-1` house and can't robber `i` house, then we find the maximum between the two choices.
44

5-
### Top-Down Recursion
6-
```kotlin
7-
fun rob(nums: IntArray): Int {
8-
return rob(nums, nums.size - 1)
9-
}
10-
11-
private fun rob(nums: IntArray, i: Int): Int {
12-
if (i == 0) {
13-
return nums[0]
14-
} else if (i == 1) {
15-
return max(nums[0], nums[1])
16-
} else {
17-
return max(rob(nums, i - 1), rob(nums, i - 2) + nums[i])
18-
}
19-
}
20-
```
21-
225
### Top-Down DP
236
```kotlin
247
fun rob(nums: IntArray): Int {
@@ -27,6 +10,8 @@ fun rob(nums: IntArray): Int {
2710
}
2811

2912
private fun rob(nums: IntArray, i: Int, memo: IntArray): Int {
13+
// It's fine to write the base case: if(i < 0) return 0
14+
3015
if (i == 0) {
3116
return nums[0]
3217
} else if (i == 1) {

leetcode/264.ugly-number-ii.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ fun nthUglyNumber(n: Int): Int {
5353
val num3 = dp[p3] * 3
5454
val num5 = dp[p5] * 5
5555

56-
dp[i] = min(num2, min(num3, num5))
56+
dp[i] = minOf(num2, minOf(num3, num5))
5757

5858
// Determine where does dp[i] come from, and increment the pointer
5959
if (dp[i] == num2) p2++

leetcode/347.top-k-frequent-elements.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,19 @@
1010
```
1111
Input: nums = [1,2,2,3,3,3], k = 1 or 2 or 3
1212
Output: [3] or [2, 3] or [1, 2, 3]
13+
14+
Input: nums = [1,1,1,2,2,2,3,3,4], k = 2
15+
Output: [1, 2], not [1, 2, 3]
16+
1: 3
17+
2: 3 k = 2
18+
3: 2
19+
4: 1
1320
```
1421
### Edge / Corner Cases
1522
* Multiple answers. (Not gonna happen, it is guaranteed that the answer is unique.)
1623
```
17-
Input: nums = [1,1,1,2,2,2], k = 2
18-
Output:
24+
nums = [1,1,1,2,2,2], k = 1
25+
nums = [1,1,1,2,2,3,3] k = 2
1926
```
2027

2128
## Heap
@@ -47,7 +54,7 @@ fun topKFrequent(nums: IntArray, k: Int): IntArray {
4754
* **Space Complexity**: `O(n) + O(k)` for hash table and heap respectively, total takes `O(n)` time.
4855

4956
## Bucket Sort
50-
We count the frequency of each element, then we create a bucket of size `nums.size + 1`, store the element value at the index `[frequency]` in the bucket.
57+
We have size `n`, and we have `n` unique elements, the maximum frequency is `n`. We can count the frequency of each element, then we create a bucket of size `nums.size + 1`, store the element value at the index `[frequency]` in the bucket.
5158

5259
```js
5360
nums = [1,2,3,4,1,2,2,3,3,3]
@@ -65,6 +72,19 @@ bucket = [
6572
[2], // 3 frequency, which is 2
6673
[3] // 4 frequency, which is 3
6774
]
75+
76+
// Or
77+
nums = [1,1,1,1]
78+
frequency = {
79+
1: 4
80+
}
81+
bucket = [
82+
[], // 0 frequency
83+
[], // 1 frequency
84+
[], // 2 frequency
85+
[], // 3 frequency
86+
[1] // 4 frequency, which is 1
87+
]
6888
```
6989

7090
Then we iterate the bucket from the end to the start, and add the value to the result list.
@@ -105,6 +125,7 @@ fun topKFrequent(nums: IntArray, k: Int): IntArray {
105125
if (bucketList.getOrNull(i) == null) continue
106126
else {
107127
results.addAll(bucketList.get(i))
128+
// The answer guaranteed to be unique, so we can break the loop when we have enough k elements.
108129
if (results.size >= k) break
109130
}
110131
}

leetcode/35.search-insert-position.md

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Output: 5
2828
```
2929

3030
## Binary Search
31-
To find the target value or the index to insert, then it indicates that we're going to search **the smallest number which is equals to or greater than `target`**.
31+
To find the target value or the index to insert, then it indicates that we're going to search **the smallest number which is equals to or greater than `target`** (it's *"floor", "left bound"*).
3232

3333
```js
3434
[1, 3, 5, 6], target = 5
@@ -121,7 +121,10 @@ target L
121121
>
122122
> https://leetcode.cn/problems/search-insert-position/solutions/8017/hua-jie-suan-fa-35-sou-suo-cha-ru-wei-zhi-by-guanp/comments/1079722
123123
124-
**Another Important Idea!!** Or you can think in this way, **we are looking for the first element that satifies the condition `target <= num`, our condition is `target <= num`**. and we have the following array, `X` indicates the numbers that doesn't meet the condition (the numbers < `target`), and `O` indicate the number met the condition (the numbers >= `target`), then the smallest number which is equals to or greater than `target` is the first `O` we want:
124+
## Alternative Thinking
125+
**Another Important Idea!!**
126+
127+
Or you can think in this way, **we are looking for the first element that satifies the condition `target <= num`, our condition is `target <= num`**. and we have the following array, `X` indicates the numbers that doesn't meet the condition (the numbers < `target`), and `O` indicate the number met the condition (the numbers >= `target`), then the smallest number which is equals to or greater than `target` is the first `O` we want:
125128
```js
126129
[X, X, X, O, O, O, O]
127130
^ // target
@@ -152,6 +155,16 @@ private fun meetCondition(target: Int, num: Int): Boolean {
152155
}
153156
```
154157

158+
### Possible `left` Range
159+
The `left` pointer is in the range `[0, size]`:
160+
```js
161+
[O, O, O, O]
162+
^ // target
163+
164+
[X, X, X, X], n
165+
^ // target
166+
```
167+
155168
### Example
156169
> Try the example with only 2 element.
157170
```js
@@ -167,8 +180,24 @@ Target Insert Position
167180
```
168181

169182
## Bonus
170-
How to find the last element which is <= `target` (Not the insert position)? => We search the last element that satisfies the condition `num <= target`. (The possible range is `[-1, size - 1]`)
183+
How to find the last element which is <= `target` (It' *"ceiling" or "right bound"*, not the insert position)?
184+
185+
It's the pattern:
186+
```js
187+
[O, O, O, X, X, X, X]
188+
^ // target
189+
```
190+
We search the last element that satisfies the condition `num <= target`. (The possible range is `[-1, size - 1]`)
171191

192+
```js
193+
-1, [X, X, X, X]
194+
^ // target
195+
196+
[O, O, O, O]
197+
^ // target
198+
```
199+
200+
### Example
172201
```js
173202
[1, 3, 7] target = 5
174203
O O X
@@ -178,7 +207,7 @@ How to find the last element which is <= `target` (Not the insert position)? =>
178207
O O O O
179208
^
180209

181-
[7, 7, 7] target = 5 // return -1
210+
-1 [7, 7, 7] target = 5 // return -1
182211
X X X
183212
^
184213
L
@@ -235,36 +264,4 @@ fun search(nums: IntArray, target: Int): Int {
235264
private fun meetCondition(target: Int, num: Int): Boolean {
236265
return num <= target
237266
}
238-
```
239-
240-
----
241-
### Deprecated Notes
242-
> The following explanation might be confused, it's OK to skip it.
243-
244-
Remember that the `left` and `right` is the valid search range (inclusive), there are the following cases:
245-
1. `middle == target`: we find the target, return the index.
246-
2. `middle < target`: we should search the right part.
247-
```js
248-
[X, X, X, O, O, O, O]
249-
M
250-
| ->
251-
L R
252-
```
253-
3. `target < middle`: we should search the left part.
254-
255-
The most hard part is case 3. `target < middle`, because we are not sure if the `middle` is the smallest number >= `target`, so we keep searching the left part:
256-
```js
257-
[X, X, X, O, O, O, O]
258-
M
259-
<- |
260-
L R // Next round search range should be.
261-
```
262-
263-
After several searching round, suppose we reach (but we don't know) the smallest number >= `target`, what range should we search for next round? Again, we are not sure if the `middle` is the smallest number >= `target`, so we search the left part:
264-
```js
265-
[X, X, X, O, O, O, O]
266-
M
267-
<- | ->
268-
R L
269-
```
270-
And this time, it breaks the while loop, and `left` pointer is the index of the smallest number >= `target`, so we return `left`.
267+
```

leetcode/746.min-cost-climbing-stairs.md

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@
22

33
We start either from index `0` or `1`, and find the min cost when reaching `n-th` step. There are two way to represent the states:
44

5+
* `to(i)` represents the cost to `i-th` step, then we calculate `to(n)`.
6+
* `from(i)` represents the cost from `i-th` step, then we calculate `min(from(n - 1), from(n - 2))`.
7+
58
```js
69
# to(i) = min(to(i - 1) + cost[i - 1], to(i - 2) + cost[i - 2])
710
# from(i) = cost[i] + min(from(i - 1), from(i - 2))
811
```
912

1013
### `To` State
11-
1214
The `to(i)` / `dp[i]` represents the cost **to** i-th step:
13-
* To `0` or `1` step cost 0, because we start from index `0` or `1`.
15+
* To `0` or `1` step cost 0, we don't have to zero cost to `0` or `1`.
1416
* The cost to `i-th` step will be the minimum of `to(i - 1) + cost[i - 1]` and `to(i - 2) + cost[i - 2]`.
17+
* We calculate `to(n)` for the result.
1518

1619
```kotlin
1720
// Recursive with memoization
@@ -21,6 +24,7 @@ fun minCostClimbingStairs(cost: IntArray): Int {
2124
return to(cost, cost.size)
2225
}
2326

27+
// Top-Down DP
2428
private fun to(cost: IntArray, i: Int): Int {
2529
if (i == 0 || i == 1) return 0
2630
if (memo.containsKey(i)) return memo[i]!!
@@ -39,10 +43,28 @@ fun minCostClimbingStairs(cost: IntArray): Int {
3943
}
4044
return dp[n]
4145
}
46+
47+
// Space Optimization
48+
fun minCostClimbingStairs(cost: IntArray): Int {
49+
if (cost.size == 2) return min(cost[0], cost[1])
50+
51+
var result = 0
52+
var step2 = 0
53+
var step1 = 0
54+
for (i in 2..cost.size) {
55+
result = min(step1 + cost[i - 1], step2 + cost[i - 2])
56+
step2 = step1
57+
step1 = result
58+
}
59+
return result
60+
}
4261
```
4362

4463
### `From` State
45-
Or we can represent `dp[i]` to be the cost that we pay in order to climb **from** `i-th` step. We have to pay `dp[i] = cost[i] + min(dp[i - 1], dp[i - 2])`.
64+
The `from(i)` / `dp[i]` represents the cost **from** i-th step:
65+
* To `0` or `1` step cost `cost[0]` and `cost[1]`.
66+
* The cost from `i-th` step will be (the minimum of `from(i - 2)` and `from(i - 1)`) + `cost[i]`.
67+
* We calculate the minimum of `from(i - 2)` and `from(i - 1)` for the result.
4668

4769
```kotlin
4870
// Time Complexity: O(n)
@@ -62,18 +84,21 @@ fun minCostClimbingStairs(cost: IntArray): Int {
6284
// Space Optimization
6385
// Time Complexity: O(n)
6486
// Space Complexity: O(1)
65-
fun minCostClimbingStairs(cost: IntArray): Int {
66-
if (cost.size == 2) return min(cost[0], cost[1])
87+
fun from(cost: IntArray): Int {
88+
val n = cost.size
89+
// n - 1
90+
var n1 = cost[1]
91+
// n - 2
92+
var n2 = cost[0]
6793

6894
var result = 0
69-
var step2 = 0
70-
var step1 = 0
71-
for (i in 2..cost.size) {
72-
result = min(step1 + cost[i - 1], step2 + cost[i - 2])
73-
step2 = step1
74-
step1 = result
95+
for (i in 2 until n) {
96+
// from(i) = cost(i) + min(from(i - 1), from(i - 2))
97+
result = cost[i] + minOf(n1, n2)
98+
n2 = n1
99+
n1 = result
75100
}
76-
return result
101+
return minOf(n2, n1)
77102
}
78103
```
79104

leetcode/array-problems.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
> * https://leetcode.com/problems/maximum-performance-of-a-team/ 3k h
3333
> * https://leetcode.com/problems/minimize-deviation-in-array/ 2k h
3434
35+
3536
### Two Pointers
3637
| Problem | Difficulty |
3738
|------------------|------------|
@@ -98,6 +99,7 @@
9899

99100
> Study guidelines: https://leetcode.com/discuss/study-guide/2166045/ (Have reviwed the problem listing)
100101
> Listing: https://leetcode.com/problem-list/52dlem1s/
102+
> Video: https://www.bilibili.com/video/BV1qY411n7Qs/?vd_source=2f62e0e1762a6703c96771d3baa35968
101103
> * https://leetcode.cn/problems/my-calendar-i/solutions/1646264/by-jiang-hui-4-pyfn/
102104
> * https://leetcode.com/problems/non-overlapping-intervals/description/ 8k m
103105
> * https://leetcode.com/problems/number-of-flowers-in-full-bloom 1k h

topics/binary-search.md

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Binary Search
22

33
## Normal
4-
The binary search is applicable when the collection is **sorted**, so try to sort the collection if it's not sorted yet.
4+
The binary search is applicable when the collection is **sorted** or the search range satisfies **monotonicity** characteristic. In this implementation, we're using inclusive range `[left, right]` to represent the searching range, and we break out the while loop when `left > right`. (The searching range is empty)
55

66
```kotlin
77
fun binarySearch(A: IntArray, target: Int): Int {
@@ -61,26 +61,30 @@ O O O O O O X X X
6161
^ // The last element that satifies the condition
6262
```
6363

64-
For example, to find the smallest (largest) number which is greater (smaller) or equal to the target: For the two problems (might contain duplicates), we can use the same conditions when `target != middle` (`<`, `>`) as normal binary search, the different part is when `target == middle`:
64+
For example, to find the smallest (largest) number which is greater (smaller) or equal to the target: For the two problems (might contain duplicates), we can use the same conditions when `target < middle` and `middle < target` as normal binary search, the different part is when `target == middle`:
6565

66-
* To find the smallest number >= `target`, we should keep searching the left half part, and return `left` pointer when while loop breaks.
66+
* To find the smallest number >= `target` (`target <= num`), we should keep searching the left half part, and return `left` pointer when while loop breaks.
6767
```js
68-
(X, _, _, _, ...)
69-
target <=
70-
L R
68+
// When breaking the while loop, the position of pointers:
69+
[X, X, X, O, O, O, O]
70+
L
71+
M
72+
R
7173
```
7274

73-
* To find the largest number <= `target`, we should search the right half part, and return `right` pointer when while loop breaks.
75+
* To find the largest number <= `target`, we should keep searching the right half part, and return `right` pointer when while loop breaks.
7476
```js
75-
(..., _, _, X)
76-
<= target
77-
L R
77+
// When breaking the while loop, the position of pointers:
78+
[O, O, O, O, X, X, X]
79+
L
80+
M
81+
R
7882
```
7983

8084
> Sample problem: [35. Search Insert Position](../leetcode/35.search-insert-position.md)
8185
8286
## Find the First/Last Position of Element in Sorted Array
83-
Given sorted array (might contain duplicates), we can use the same approach mentioned above to find the first/last position of element in sorted array. We apply the same conditions when `target != middle` (`<`, `>`) as normal binary search, the different part is when `target == middle`:
87+
Given sorted array (might contain duplicates), we can use the same approach mentioned above to find the first/last position of element in sorted array. We apply the same conditions when `target < middle` and `middle < target` as normal binary search, the different part is when `target == middle`:
8488

8589
* To find the first position, we should keep searching the left part because we don't know if current `middle` is the first element, and return `left` pointer when while loop breaks.
8690
```js

0 commit comments

Comments
 (0)