Skip to content

Commit 371b7bd

Browse files
committed
Update problem solving techniques for tree, heap, binary searcn, linked list, stack and queue.
1 parent c804a9a commit 371b7bd

11 files changed

+315
-177
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
## [1642. Furthest Building You Can Reach](https://leetcode.com/problems/furthest-building-you-can-reach)
22

33
### Greedy
4-
We use ladder greedily first, when there is not enough ladder, we replace the shortest ladder with bricks.
4+
We don't know when to use ladder or bricks, so we try to use ladder first, when there is not enough ladder, we use bricks instead. We use ladder greedily first, when there is not enough ladder, we replace the shortest ladder with bricks.
5+
6+
> 那就是我無腦用梯子,等梯子不夠用了,我們就要開始事後諸葛亮了,要是前面用磚頭就好了。 [Source](https://leetcode-solution-leetcode-pp.gitbook.io/leetcode-solution/thinkings/heap-2#ji-qiao-san-shi-hou-xiao-zhu-ge)
57
68
```js
79
[6, 5, 5, 10, 12, 100, 106, 208, 207, 208], 10 bricks, 2 ladders

leetcode/560.subarray-sum-equals-k.md

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ s.t. pre[i] = pre[j] - k
8080
we can apply the same approach in problem [1. Two Sum](../leetcode/1.two-sum.md), we can iterate `j` to sum up the `prefixSum`, then check if `prefixSum - k` (that is `pre[j] - k`, we are looking for `pre[i]`) exists in the `prefixSum` map. If it exists, then we found a subarray with sum `k`, and we add the count of the subarray to the result.
8181

8282
Here are some cruial points to note:
83-
1. We don't maintain the `prefixSum` array because we can iterate once to calculate the `prefixSum`.
84-
1. For the case `prefixSum == k`, we have to add the count of `prefixSum == k` to the result, so we initialize the `prefixSum` map with `0` as key and `1` as value.
83+
* We don't maintain the `prefixSum` array because we can iterate once to calculate the `prefixSum`.
84+
* For the case `prefixSum == k`, we have to add the count of `prefixSum == k` to the result, so we initialize the `prefixSum` map with `0` as key and `1` as value.
8585

8686
```js
8787
k = 2
@@ -90,13 +90,13 @@ prefix = 1 2 4
9090
* --> prefixSum - k = 0
9191
```
9292

93-
1. If `prefixSum - k` exists, we don't increment the count by 1 because it leads to WA, there might be multiple `prefixSum - k` exists, so we sum up the count by the number of `prefixSum - k` exists. (Input `[0, 0, 0]`, k = `0`)
93+
* If `prefixSum - k` exists, we don't increment the count by 1 because it leads to WA, there might be multiple `prefixSum - k` exists, so we sum up the count by the number of `prefixSum - k` exists. (Input `[0, 0, 0]`, k = `0`)
9494

9595
```js
9696
input = 0, 0, 0
9797
prefix= 0, 0, 0
9898
```
99-
1. This problem can't be solved by sliding window, because there is no good way to decide when to shrink the window when the number is negative (`nums = [-1, -1, 1]`) or contains `0` (`nums = [0, 1, 1, 0]` and `k = 2`). Based on the characteristics of sliding window:
99+
* This problem can't be solved by sliding window, because there is no good way to decide when to shrink the window when the number is negative (`nums = [-1, -1, 1]`) or contains `0` (`nums = [0, 1, 1, 0]` and `k = 2`). Based on the characteristics of sliding window:
100100
* If wider window is valid, then narrower window is also valid.
101101
```js
102102
k = 3
@@ -159,9 +159,4 @@ fun subarraySum(nums: IntArray, k: Int): Int {
159159
```
160160

161161
* **Time Complexity**: `O(n)`.
162-
* **Space Complexity**: `O(n)`.
163-
164-
165-
k = 2
166-
value = [1, 1, 2]
167-
prefix = 1, 2, 4
162+
* **Space Complexity**: `O(n)`.

topics/array.md

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,24 +65,13 @@ Comparison to Linked List, see [Linked List](../topics/linked-list.md) topic.
6565
|--------------------------------------------------------|---------------------------------------------------------------------------------------|--------------------------------|
6666
| 1. Random access.<br>2. No `next` field, saving space. (vs Linked List) | 1. Bad at insert/delete. (Copy to new array)<br>2. Bad at resize. (Copy to new array) | 1. Fast access.<br>2. Fix size |
6767

68-
## Tips for [Problem Solving](./leetcode-solutions.md#array)
69-
* Mind the bound or size of array. Think about empty array or with few element (1, 2, or less than the problem requirement).
70-
* Is the array sorted (partially)? Yes, try *binary search*. No, try to sort first?
71-
* Swap or ignore element (only take the element met the requirement)
72-
* We can iterate array from left to right, also from *right to left*.
73-
* `O(n)` time complexity **doesn't** mean you can only iterate the array **once**. Iterate the array several times might help solve the problem, for example, pre-computation (iterate array at least one time first) using hashing might be useful.
74-
* For in-place operation or `O(1)` space complexity, use array (index) itself as a hash table. For example, the value of array ranges from 1 to `n`, where `n` is the size of array, then we can use the *index* to represent.
75-
* Array in Kotlin:
68+
## Array in Kotlin
7669
```kotlin
7770
val array = IntArray(3) { 5 } // [5, 5, 5]
7871
array.sliceArray(1..5) // subarray of A[1:5]
7972
array.sliceArray(3 until array.size) // subarray of A[3:]
8073
```
8174

82-
## Sliding Window Approach
83-
The every character will enter and exit the window at most once, so the time complexity is `O(n)`.
84-
85-
8675
## Resources
8776
- [X] [MIT 6.006 Introduction to Algorithm - Lecture 2: Data Structures and Dynamic Arrays](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-006-introduction-to-algorithms-spring-2020/lecture-videos/lecture-2-data-structures-and-dynamic-arrays/)
8877
- [ ] Kotlin document

topics/binary-search.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ while (left <= right) {
5151
return result
5252
```
5353

54-
## Find the first (last) element that satifies the condition
54+
## Find the first/left-most (last/right-most) element that satifies the condition
5555
```js
5656
X X X O O O O O
5757
^ // The first element that satifies the condition

topics/dynamic-programming.md

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -611,19 +611,6 @@ fun printLCS(parent: Array<IntArray>, x: Int, y: Int) {
611611
* **Time Complexity**: `O(m * n)`, for `m`, `n` is the length of `A` and `B`.
612612
* **Space Complexity**: `O(m * n)` for dp 2D table.
613613

614-
## Tips for [Problem Solving](../topics/leetcode-solutions.md#dynamic-programming)
615-
616-
### When to use DP?
617-
The problem meets the both two characteristics:
618-
1. Solve the optimal problem (often, but not always), for example:
619-
* The minimum cost
620-
* The maximum profit
621-
* How many ways are there to do...
622-
* What's the longest/shortest possible...
623-
2. The solution of original problem comes from eariler calculated solution (from the overlapping subproblems), that is, the later step will be affected by the eariler step.
624-
625-
Sometimes, only meets the first but not the second might be the greedy algorithm, not DP. For some problems, we have to return the optimal value among DP table, not just `dp[0]` or `dp[n]` itself.
626-
627614
### Problem Solving Steps
628615

629616
#### 5 Steps of Dynamic Programming

topics/greedy.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A *greedy algorithm* always makes the choice that looks best at the moment, it m
44
We shall consider a [dynamic programming](../topics/dynamic-programming.md) solution (including steps) and show that we can always make greedy choices to arrival the optimal solution.
55

66
## Steps of Greedy
7-
1. Cast the optimization problem as one in which we make a choice and are left with one subproblem to solve. (Top-down fashion: making a greedy choice, reduce the problems to a smaller subproblems)
7+
1. Making a greedy choice, reduce the problems to a smaller subproblems.
88
2. Prove that making the greedy choice is always safe.
99
3. We conbime an optimal solutions to the subproblems with the greedy choice, we can arrive at the optimal solution to the original problem.
1010

@@ -49,9 +49,4 @@ fun knapsackFractional(): Float {
4949
}
5050
return totalValues
5151
}
52-
```
53-
54-
## Resources
55-
- [X] CLRS
56-
- [ ] https://github.com/youngyangyang04/leetcode-master#%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95
57-
- [X] [Tech Interview Cheat Sheet](https://github.com/TSiege/Tech-Interview-Cheat-Sheet#greedy-algorithms)
52+
```

topics/heap.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,11 @@ fun heapSort(A) {
191191
* **Time Complexity**: `buildMapHeap(A)` takes `O(n)`, and `n - 1` elements run `heapifyDown()`, which takes `O(n - 1) * O(lg n)` = `O(n lg n)`.
192192

193193
## Tips for [Problem Solving](../topics/leetcode-solutions.md#heap)
194-
* Heap is good at find the top/smallest K of xxx or median. (or using binary search if there is sorted list) We also can use **Quickselect** to find *k*th smallest item in an unordered list. (See problem [215. Kth Largest Element in an Array](../leetcode/215.kth-largest-element-in-an-array.md))
194+
* Heap is good at find the top/smallest K of xxx or median. (or using binary search if there is sorted list) We also can use **Quickselect** to find *k*th smallest item in an unordered list.
195195
* For top k problems, you can use:
196196
* Build max heap from all items, and pop `k - 1` times, and the peek will be the top K result.
197197
* Using min heap with `k` items, we add item one by one, and pop (the min value) if heap size > `k` as adding item. The remaining heap will be top K results **but in reversed order**, make sure to reverse the result.
198-
* For frequency sorting, we can use *bucket sort*, see problem [347. Top K Frequent Elements](../leetcode/347.top-k-frequent-elements.md)
198+
* For frequency sorting, we can use *bucket sort*, see problem
199199
* For some problems to find the max/min value **dynamically** (after some operations, such adding some numbers then find the max number), then it might be able to use heap to solve. ([264. Ugly Number II](https://leetcode.com/problems/ugly-number-ii/))
200200
* Heap in Kotlin:
201201
```kotlin

topics/leetcode-solutions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
#### Problem Listing
110110
> * https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string-ii/ 5k m
111111
> * https://leetcode.com/problems/accounts-merge/ 5k m
112+
> * Solved: https://leetcode.com/problems/check-if-two-string-arrays-are-equivalent/description/ 3k e
112113
> ----
113114
> * https://leetcode.com/problems/repeated-string-match/ 2k m
114115
> * https://leetcode.com/problems/distinct-subsequences-ii/ 2k h
@@ -308,6 +309,7 @@
308309
|[2265. Count Nodes Equal to Average of Subtree](../leetcode/2265.count-nodes-equal-to-average-of-subtree.md)|Medium|
309310

310311
> * Solved: https://leetcode.com/problems/find-largest-value-in-each-tree-row/ 3k m
312+
> * Solved: https://leetcode.com/problems/construct-string-from-binary-tree/ 3k e
311313
> * https://leetcode.com/problems/count-complete-tree-nodes 8k e
312314
> * https://leetcode.com/problems/sum-root-to-leaf-numbers/ 7k m
313315
> * https://leetcode.com/problems/find-duplicate-subtrees 6k m

topics/linked-list.md

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -561,42 +561,7 @@ Linked list with the last node has reference to the head.
561561

562562
> // TODO
563563
564-
## Tips for [Problem Solving](./leetcode-solutions.md#linked-list)
565-
* Corner cases:
566-
* **Empty linked list** (before operation or **after!**, such as deleting the only node)
567-
* Linked list with **one / two nodes**
568-
* Linked list has cycles. Clarify before solving problem! And pay attention to the result after performing the functions.
569-
570-
```js
571-
1. head -> null
572-
2. head -> A -> null
573-
3. head -> A -> B -> null
574-
```
575-
For some cases we have to insert when head is null or deleting head and after that the head will be null, then we can introduct *sentinel node* to help.
576-
577-
```kotlin
578-
fun solveProblem(head?: Node): Node? {
579-
val sentinel = Node(-1)
580-
var node: Node? = sentinel
581-
/// do something to modify the `node`
582-
583-
return sentinel.next
584-
}
585-
```
586-
587-
* Pay attention to operate on the specific node before or after, especially on head and last node or the pointer nodoe after while loop.
588-
* **Drawing** could be really help!!
589-
* Get familiar with the following operations:
590-
* Reverse in-place or update the node references (be careful of cycle references)
591-
* Merge (connect/chain) two linked lists
592-
* Count the node number
593-
* Find the middle node using two pointers technique
594-
* Fast/slow pointers to solve cycle or interaction problems.
595-
* [876. Middle of the Linked List](../leetcode/876.middle-of-the-linked-list.md)
596-
* [141. Linked List Cycle](../leetcode/141.linked-list-cycle.md)
597-
* [142. Linked List Cycle II](../leetcode/142.linked-list-cycle-ii.md)
598-
599-
* `LinkedList` in Kotlin:
564+
## LinkedList in Kotlin:
600565
```kotlin
601566
val linkedList = LinkedList<Int>()
602567
linkedList.addFirst(1)
@@ -608,7 +573,6 @@ linkedList.removeLast()
608573
linkedList.first()
609574
linkedList.last()
610575
```
611-
> [Nice post](https://leetcode-solution-leetcode-pp.gitbook.io/leetcode-solution/thinkings/linked-list) to read that need to keep in mind.
612576

613577
## Resources
614578
- Fundamental of Data Structure

0 commit comments

Comments
 (0)