Skip to content

Commit 352f49c

Browse files
committed
Add some solutions to new problems
1642. Furthest Building You Can Reach 278. First Bad Version 983. Minimum Cost For Tickets 287. Find the Duplicate Number 669. Trim a Binary Search Tree 2115. Find All Possible Recipes from Given Supplies 103. Binary Tree Zigzag Level Order Traversal 219. Contains Duplicate II 856. Score of Parentheses 617. Merge Two Binary Trees 1046. Last Stone Weight]() 645. Set Mismatch 684. Redundant Connection
1 parent 90341a4 commit 352f49c

24 files changed

+887
-196
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
## [103. Binary Tree Zigzag Level Order Traversal](https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal)
2+
3+
```kotlin
4+
fun zigzagLevelOrder(root: TreeNode?): List<List<Int>> {
5+
val results = mutableListOf<List<Int>>()
6+
if (root == null) return results
7+
val queue = ArrayDeque<TreeNode>()
8+
queue.addLast(root)
9+
// Odd: left to right, even: right to left
10+
var level = 1
11+
while (queue.isNotEmpty()) {
12+
val size = queue.size
13+
val list = LinkedList<Int>()
14+
for (i in 0 until size) {
15+
val node = queue.removeFirst()
16+
if (level % 2 != 0) {
17+
list.add(node.`val`)
18+
} else {
19+
list.addFirst(node.`val`)
20+
}
21+
if (node.left != null) {
22+
queue.addLast(node.left)
23+
}
24+
if (node.right != null) {
25+
queue.addLast(node.right)
26+
}
27+
}
28+
results.add(list)
29+
level++
30+
}
31+
32+
return results
33+
}
34+
```

leetcode/1046.last-stone-weight.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
## [1046. Last Stone Weight](https://leetcode.com/problems/last-stone-weight)
2+
3+
```kotlin
4+
fun lastStoneWeight(stones: IntArray): Int {
5+
val maxHeap = PriorityQueue<Int>() { n1, n2 -> n2 - n1 }
6+
for (stone in stones) maxHeap.add(stone)
7+
8+
while (maxHeap.isNotEmpty()) {
9+
val first = maxHeap.poll()
10+
if (maxHeap.isEmpty()) return first
11+
val second = maxHeap.poll()
12+
13+
if (first != second) maxHeap.add(abs(first - second))
14+
}
15+
return 0
16+
}
17+
```
18+
19+
* **Time Complexity**: `O(n lg n)`, comparsion take `n - 1` times and every time take `lg n` to poll the largest two stones.
20+
* **Space Complexity**: `O(n)`.

leetcode/124.binary-tree-maximum-path-sum.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ class Solution {
4545
}
4646
}
4747
```
48+
49+
* **Time Complexity**: `O(n)`.
50+
* **Space Complexity**: `O(n)`.
51+
4852
### Failed Cases
4953
```js
5054
-2
@@ -58,4 +62,8 @@ class Solution {
5862
-2
5963
/ \
6064
1 3
65+
```
66+
67+
```js
68+
-3
6169
```
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
## [1642. Furthest Building You Can Reach](https://leetcode.com/problems/furthest-building-you-can-reach)
2+
3+
We use ladder first if we have enough ladder, but if we don't have enough ladder, then we change the smallest height difference to use brick if the number of brick is enough for that smallest height difference.
4+
5+
```js
6+
[6, 5, 5, 10, 12, 100, 106, 208, 207, 208], 10 bricks, 2 ladders
7+
diff -1, 0, 5, 2, 82, 6, 102, -1,
8+
* *
9+
// We should use ladder here
10+
```
11+
12+
```kotlin
13+
fun furthestBuilding(heights: IntArray, bricks: Int, ladders: Int): Int {
14+
var furthestIndex = 0
15+
val minHeap = PriorityQueue<Int>()
16+
var remainingBricks = bricks
17+
18+
// Iterate i from the 2nd height to that last
19+
for (i in 1 until heights.size) {
20+
// Calculate the height diffence
21+
val heightDiff = heights[i] - heights[i - 1]
22+
23+
// If difference <= 0, we can move without any bricks or ladders
24+
if (heightDiff <= 0) {
25+
furthestIndex = i
26+
} else {
27+
minHeap.add(heightDiff)
28+
// We have enough ladder, just use it
29+
if (minHeap.size <= ladders) {
30+
furthestIndex = i
31+
} else {
32+
// We don't have enough ladder, then try to change
33+
// the smallest height difference
34+
// to use the remaining brick.
35+
if (minHeap.isNotEmpty() && minHeap.peek() <= remainingBricks) {
36+
remainingBricks -= minHeap.poll()
37+
furthestIndex = i
38+
} else {
39+
break
40+
}
41+
}
42+
}
43+
}
44+
return furthestIndex
45+
}
46+
```
47+
48+
* **Time Complexity**: `O(n lg k)`, `k` is the number of ladders.
49+
* **Space Complexity**: `O(lg k)`

leetcode/17.letter-combinations-of-a-phone-number.md

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
## [17. Letter Combinations of a Phone Number](https://leetcode.com/problems/letter-combinations-of-a-phone-number/)
22

33
```kotlin
4-
private val letterMapping = hashMapOf<String, String>(
4+
private val mapping = hashMapOf<String, String>(
55
"2" to "abc",
66
"3" to "def",
77
"4" to "ghi",
@@ -11,29 +11,24 @@ private val letterMapping = hashMapOf<String, String>(
1111
"8" to "tuv",
1212
"9" to "wxyz"
1313
)
14-
1514
private val results = mutableListOf<String>()
1615

1716
fun letterCombinations(digits: String): List<String> {
1817
if (digits.isEmpty()) return results
19-
val lettersList = mutableListOf<String>()
20-
for (digit in digits) {
21-
lettersList.add(letterMapping[digit.toString()]!!)
22-
}
23-
dfs(lettersList, mutableListOf<String>())
18+
dfs(digits, 0, mutableListOf<String>())
2419
return results
2520
}
2621

27-
private fun dfs(lettersList: List<String>, combination: MutableList<String>) {
28-
if (combination.size == lettersList.size) {
22+
private fun dfs(digits: String, index: Int, combination: MutableList<String>) {
23+
if (combination.size == digits.length) {
2924
results.add(combination.joinToString(""))
30-
return
25+
return
3126
}
3227

33-
val letters = lettersList[combination.size]
28+
val letters = mapping[digits[index].toString()]!!
3429
for (letter in letters) {
3530
combination.add(letter.toString())
36-
dfs(lettersList, combination)
31+
dfs(digits, index + 1, combination)
3732
combination.removeAt(combination.size - 1)
3833
}
3934
}

leetcode/207.course-schedule.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## [207. Course Schedule](https://leetcode.com/problems/course-schedule/)
22

3+
### DFS
34
The problem is equivalent to detect a cycle in a directed graph. If there exists a cycle, then we can't find the topological sort.
45

56
```kotlin
@@ -48,6 +49,65 @@ class Solution {
4849
}
4950
```
5051

52+
* **Time Complexity**: `O(m + n)`, `m` is the number of courses, `n` is the number of prerequisites.
53+
* **Space Complexity**: `O(m + n)`, we build a adjacent list that takes `O(m + n)`, and enque all courses that takes `O(n)`.
54+
55+
### BSF
56+
BFS approach uses the indegrees of every vertex, for a course (vertex), the indegrees represents how many prerequisites we have to take before so that we can finish the current one.
57+
58+
For example, the `prerequisites` is `[[2, 0], [2, 1]]`, that means that I have to finish course `0` and `1` so that I can finish `2`, that can be represented in graph like this:
59+
60+
```js
61+
0 -> 2
62+
1 -> 2
63+
```
64+
65+
So course (vertex) `2` has 2 indegree edges, and the number of indegrees is `2`.
66+
67+
To solve this problem, we build a graph with indegree array for every courses (vertices), and enqueue course if I finish all its prerequisites, and count how many courses did I finished.
68+
69+
```kotlin
70+
fun canFinish(numCourses: Int, prerequisites: Array<IntArray>): Boolean {
71+
val edges = Array<MutableList<Int>>(numCourses) { _ -> mutableListOf<Int>() }
72+
73+
val inDegrees = IntArray(numCourses)
74+
for (p in prerequisites) {
75+
val before = p[1]
76+
val after = p[0]
77+
// p[1] -> p[0]
78+
edges[before].add(after)
79+
inDegrees[after]++
80+
}
81+
82+
// Queue enques all the course that we can study now. (no or finished all prerequisites)
83+
val queue = ArrayDeque<Int>()
84+
for (i in 0 until numCourses) {
85+
// Study all the courses without any prerequisites.
86+
if (inDegrees[i] == 0) queue.addLast(i)
87+
}
88+
89+
var studiedCourses = 0
90+
while (queue.isNotEmpty()) {
91+
val course = queue.removeFirst()
92+
studiedCourses++
93+
94+
// Find all courses after the current course
95+
edges[course].forEach { afterCourse ->
96+
inDegrees[afterCourse]--
97+
98+
// If all prerequiistes are finished, then I can study this after course.
99+
if (inDegrees[afterCourse] == 0) {
100+
queue.addLast(afterCourse)
101+
}
102+
}
103+
}
104+
return studiedCourses == numCourses
105+
}
106+
```
107+
108+
* **Time Complexity**: As same as DFS.
109+
* **Space Complexity**: As same as DFS.
110+
51111
### Clarification Questions
52112
1. Are all the prerequisites pair unique?
53113
2. What if `prerequisites` is empty? (but `numCourses` is 1 or greater than 1)
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
## [2115. Find All Possible Recipes from Given Supplies](https://leetcode.com/problems/find-all-possible-recipes-from-given-supplies)
2+
3+
Suppose we the following recipes, ingredients and supplies:
4+
```js
5+
Recipes = [R2, R1]
6+
Ingredients = [[C, R1, D, B], [A, B]]
7+
Supplies = [A, B, C, D]
8+
```
9+
10+
For each recipe `recipes[i]`, we have the `ingredients[i]` that can make it, we take them as edges from ingredient to recipe:
11+
12+
```js
13+
// Graph (visualization)
14+
C, R1, D, B => R2
15+
A, B => R1
16+
```
17+
18+
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.
19+
20+
So we build the graph from ingredients and count the indegrees for every recipes, and run BFS.
21+
```js
22+
// Graph (data structure)
23+
C: [R2]
24+
R1:[R2]
25+
D: [R2]
26+
B: [R2, R1]
27+
A: [R1]
28+
29+
// Indegrees:
30+
R2: 4
31+
R1: 2
32+
```
33+
34+
### Topological Sort (BFS)
35+
```kotlin
36+
fun findAllRecipes(recipes: Array<String>, ingredients: List<List<String>>, supplies: Array<String>): List<String> {
37+
val graph = hashMapOf<String, MutableList<String>>()
38+
val indegrees = hashMapOf<String, Int>()
39+
for (i in 0 until ingredients.size) {
40+
for (ingredient in ingredients[i]) {
41+
if (!graph.containsKey(ingredient)) graph[ingredient] = mutableListOf<String>()
42+
graph[ingredient]!!.add(recipes[i])
43+
}
44+
indegrees[recipes[i]] = ingredients[i].size
45+
}
46+
47+
val queue = ArrayDeque<String>()
48+
for (supply in supplies) {
49+
queue.addLast(supply)
50+
}
51+
52+
val results = mutableListOf<String>()
53+
while (queue.isNotEmpty()) {
54+
val current = queue.removeFirst()
55+
graph[current]?.forEach { r ->
56+
var indegree = indegrees[r]!!
57+
// Remember to check this, it means not finished.
58+
if (indegree > 0) {
59+
indegree--
60+
// We can make it
61+
if (indegree == 0) {
62+
results.add(r)
63+
queue.addLast(r)
64+
}
65+
indegrees[r] = indegree
66+
}
67+
}
68+
}
69+
return results
70+
}
71+
```
72+
73+
* **Time Complexity**: `O(R*I + S + R)` = `O(R*I + S)` where `R`, `I`, `S` represent the number of recipes, ingredients and supplies.
74+
* **Space Complexity**: `O(R*I + S)` for graph and queue.
75+
76+
### ~~Brute Force~~
77+
```kotlin
78+
fun findAllRecipes(recipes: Array<String>, ingredients: List<List<String>>, supplies: Array<String>): List<String> {
79+
80+
val finishedRecipes = hashSetOf<String>()
81+
val suppliesSet = hashSetOf<String>()
82+
for (s in supplies) { suppliesSet.add(s) }
83+
84+
var recipeIndex = 0
85+
while (recipeIndex < recipes.size) {
86+
if (finishedRecipes.contains(recipes[recipeIndex])) {
87+
recipeIndex++
88+
continue
89+
}
90+
val ingredient = ingredients[recipeIndex]
91+
var canMake = true
92+
for (i in 0 until ingredient.size) {
93+
if (!suppliesSet.contains(ingredient[i]) && !finishedRecipes.contains(ingredient[i])) {
94+
canMake = false
95+
break
96+
}
97+
}
98+
99+
if (canMake) {
100+
finishedRecipes.add(recipes[recipeIndex])
101+
recipeIndex = 0
102+
} else {
103+
recipeIndex++
104+
}
105+
}
106+
return ArrayList<String>(finishedRecipes)
107+
}
108+
```
109+
110+
* **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.
111+
* **Space Complexity**: `O(R + S)`.
112+
113+
114+
```js
115+
// Recipes = [R2, R1]
116+
// Ingredients = [[C, R1, D, B], [A, B]]
117+
// Supplies = [A, B, C, D]
118+
119+
// Graph (visualization)
120+
// C, R1, D, B => R2
121+
// A, B => R1
122+
123+
// Graph (data structure)
124+
C: [R2]
125+
R1:[R2]
126+
D: [R2]
127+
B: [R2, R1]
128+
A: [R1]
129+
130+
// Indegrees:
131+
R2: 0
132+
R1: 0
133+
134+
Queue: , , , , R2
135+
Current: R2
136+
137+
Results: R1, R2
138+
```

0 commit comments

Comments
 (0)