Skip to content

Commit 8a2595f

Browse files
committed
Update notes and problems
1 parent ac5867f commit 8a2595f

File tree

56 files changed

+1756
-1206
lines changed

Some content is hidden

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

56 files changed

+1756
-1206
lines changed

leetcode/108.convert-sorted-array-to-binary-search-tree.md

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,5 @@
11
## [108. Convert Sorted Array to Binary Search Tree](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/)
22

3-
## Clarification Questions
4-
* No, it's clear from problem description.
5-
6-
## Test Cases
7-
### Normal Cases
8-
```
9-
Input:
10-
Output:
11-
```
12-
### Edge / Corner Cases
13-
*
14-
```
15-
Input:
16-
Output:
17-
```
18-
193
### Subarray
204
```kotlin
215
fun sortedArrayToBST(nums: IntArray): TreeNode? {

leetcode/1129.shortest-path-with-alternating-colors.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ fun shortestAlternatingPaths(n: Int, redEdges: Array<IntArray>, blueEdges: Array
6565
// Regular BFS to update the shortest distance
6666
while (queue.isNotEmpty()) {
6767
val node = queue.removeFirst()
68+
val current = node.index
69+
val isRed = node.isRed
70+
val distance = node.distance
71+
6872
// We update the distance for every node when visiting the particular node
6973
distances[current] = minOf(distances[current], distance)
7074

leetcode/1146.snapshot-array.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ get(snapId=1) = 1
4747
get(snapId=2) = 1
4848
```
4949

50+
> 接下来我们需要考虑一个效率的问题。我们每调用一次snap()是否需要给每个元素都新建一次快照呢?显然如果大多数元素都没有更新过的话,再添加一次快照的效率不高。所以我们可以设置一个changed的集合,里面只存放上一次snap()之后变动过的元素,也就是被set()过的元素。 我们会发现对于每个元素而言,它被记录的snapId并不是连续的。所以我们应该在snaps[index]里面找到最后一个小于等于snapId的那个时间戳。
51+
5052
## Brute Force (MLE)
5153
We just save all snapshots. It wastes memory if we have a large array but only a few elements are modified.
5254

leetcode/1162.as-far-from-land-as-possible.md

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,11 @@
11
## [1162. As Far from Land as Possible](https://leetcode.com/problems/as-far-from-land-as-possible/)
22

3-
## Clarification Questions
4-
* No, it's clear from problem description.
5-
6-
## Test Cases
7-
### Normal Cases
8-
```
9-
Input:
10-
Output:
11-
```
12-
### Edge / Corner Cases
13-
*
14-
```
15-
Input:
16-
Output:
17-
```
3+
> TODO: Review the notes + implementations
184
19-
```kotlin
20-
val directions = arrayOf(
21-
intArrayOf(-1, 0),
22-
intArrayOf(1, 0),
23-
intArrayOf(0, -1),
24-
intArrayOf(0, 1)
25-
)
5+
### BFS
6+
The problem is looking for the farest water cell from the nearest land cell. We can start from the land cells and traverse the water cells to find the farest distance.
267

8+
```kotlin
279
fun maxDistance(grid: Array<IntArray>): Int {
2810
val n = grid.size
2911
var maxDistance = 0

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

Lines changed: 121 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,156 @@
11
# [1254. Number of Closed Islands](https://leetcode.com/problems/number-of-closed-islands/)
22

33
## Traversal From Islands
4-
We can traverse all the islands, and check if current island is closed. We can use DFS or BFS to traverse the grid.
4+
We can traverse all the islands, and check if current island is closed. We can use DFS or BFS to traverse the grid. Remember! We have to traverse all the cells of the island to check if it's closed even if we found a cell that is not closed.
55

66
```kotlin
7-
class Solution {
8-
private val directions = arrayOf(
9-
intArrayOf(-1, 0),
10-
intArrayOf(1, 0),
11-
intArrayOf(0, -1),
12-
intArrayOf(0, 1)
13-
)
14-
15-
private val visited = 2
16-
fun closedIsland(grid: Array<IntArray>): Int {
17-
val m = grid.size
18-
val n = grid[0].size
19-
var count = 0
20-
for (i in 0 until m) {
21-
for (j in 0 until n) {
22-
if (grid[i][j] == 0) {
23-
if (dfs(grid, i, j)) count++
24-
}
7+
fun closedIsland(grid: Array<IntArray>): Int {
8+
val m = grid.size
9+
val n = grid[0].size
10+
val visited = HashSet<Pair<Int, Int>>()
11+
var count = 0
12+
for (i in 0 until m) {
13+
for (j in 0 until n) {
14+
if (grid[i][j] == 0 && visited.contains(i to j).not()) {
15+
if (dfs(grid, i, j, visited)) count++
16+
// if (bfs(grid, i, j, visited)) count++
2517
}
2618
}
27-
return count
2819
}
20+
return count
21+
}
2922

30-
private fun dfs(grid: Array<IntArray>, x: Int, y: Int): Boolean {
31-
val m = grid.size
32-
val n = grid[0].size
33-
if (x !in 0 until m || y !in 0 until n) return false
34-
if (grid[x][y] == 1) return true
35-
if (grid[x][y] == visited) return true
23+
private fun dfs(grid: Array<IntArray>, x: Int, y: Int, visited: HashSet<Pair<Int, Int>>): Boolean {
24+
val m = grid.size
25+
val n = grid[0].size
26+
visited.add(x to y)
27+
var result = true
28+
for (d in directions) {
29+
val newX = x + d[0]
30+
val newY = y + d[1]
31+
if (newX !in 0 until m || newY !in 0 until n) result = false // Out of boundary, it affects the result.
32+
else if (visited.contains(newX to newY)) continue // Skip, don't change the result
33+
else if (grid[newX][newY] == 1) continue // We initialize the result as true, we keep it true (won't change it) untili we reach the boundary.
34+
else result = dfs(grid, newX, newY, visited) && result
35+
}
36+
return result
37+
}
3638

37-
grid[x][y] = visited
39+
private fun dfs(grid: Array<IntArray>, x: Int, y: Int, visited: HashSet<Pair<Int, Int>>): Boolean {
40+
val m = grid.size
41+
val n = grid[0].size
42+
if (x !in 0 until m || y !in 0 until n) return false
43+
if (visited.contains(x to y)) return true
44+
if (grid[x][y] == 1) return true
3845

39-
var result = true
40-
directions.forEach { d ->
41-
// result = result & dfs(grid, x + d[0], y + d[1]) will not work, we have to traverse all the cells and then return the result.
42-
// but we use `&&` to short-circuit the evaluation, it won't traverse all the cells of the same island.
43-
result = dfs(grid, x + d[0], y + d[1]) && result
44-
}
45-
return result
46+
visited.add(x to y)
47+
var result = true
48+
for (d in directions) {
49+
val newX = x + d[0]
50+
val newY = y + d[1]
51+
// result = result & dfs(grid, x + d[0], y + d[1]) will not work, we have to traverse all the cells and then return the result.
52+
// but we use `&&` to short-circuit the evaluation, it won't traverse all the cells of the same island.
53+
result = dfs(grid, newX, newY, visited) && result
4654
}
55+
return result
56+
}
4757

48-
private fun bfs(grid: Array<IntArray>, i: Int, j: Int): Boolean {
49-
val m = grid.size
50-
val n = grid[0].size
51-
val q = ArrayDeque<Pair<Int, Int>>()
52-
q.addLast(i to j)
53-
var closed = true
54-
while (q.isNotEmpty()) {
55-
val pair = q.removeFirst()
56-
val x = pair.first
57-
val y = pair.second
58-
59-
if (x !in 0 until m || y!in 0 until n) {
60-
closed = false
61-
continue
58+
private fun bfs(grid: Array<IntArray>, sourceX: Int, sourceY: Int, visited: HashSet<Pair<Int, Int>>): Boolean {
59+
val m = grid.size
60+
val n = grid[0].size
61+
val queue = ArrayDeque<Pair<Int, Int>>()
62+
queue.addLast(sourceX to sourceY)
63+
visited.add(sourceX to sourceY)
64+
var result = true
65+
while (queue.isNotEmpty()) {
66+
val (x, y) = queue.removeFirst()
67+
for (d in directions) {
68+
val newX = x + d[0]
69+
val newY = y + d[1]
70+
if (newX !in 0 until m || newY !in 0 until n) result = false
71+
else if (visited.contains(newX to newY)) continue
72+
else if (grid[newX][newY] == 1) continue
73+
else {
74+
queue.addLast(newX to newY)
75+
visited.add(newX to newY)
6276
}
63-
if (grid[x][y] != 0) continue
64-
grid[x][y] = visited
65-
directions.forEach { d ->
66-
q.addLast(x + d[0] to y + d[1])
77+
}
78+
}
79+
return result
80+
}
81+
82+
private fun bfs(grid: Array<IntArray>, sourceX: Int, sourceY: Int, visited: HashSet<Pair<Int, Int>>): Boolean {
83+
val m = grid.size
84+
val n = grid[0].size
85+
val queue = ArrayDeque<Pair<Int, Int>>()
86+
queue.addLast(sourceX to sourceY)
87+
var result = true
88+
while (queue.isNotEmpty()) {
89+
val (x, y) = queue.removeFirst()
90+
if (x !in 0 until m || y !in 0 until n) result = false
91+
else if (visited.contains(x to y)) continue
92+
else if (grid[x][y] == 1) continue
93+
else {
94+
visited.add(x to y)
95+
for (d in directions) {
96+
val newX = x + d[0]
97+
val newY = y + d[1]
98+
queue.addLast(newX to newY)
6799
}
68100
}
69-
return closed
70101
}
102+
return result
71103
}
72104
```
73105

74106
## Traversal From Boundary
75-
To find the closed island, we can find non-closed islands first, then find the closed islands. How can we find the non-closed islands? We can start searching from the edges of the grid, the islands which are connected to the edges are non-closed islands. We can mark them as invalid during traversal. Then we can find the closed islands by traversing the grid again.
107+
To find the closed island, we can find open islands first, then find the closed islands. We can start searching from the edges of the grid, the islands which are connected to the edges are non-closed islands. We can mark them as invalid during traversal. Then we can find the closed islands by traversing the grid again.
76108

77109
* We traversal (either DFS or BFS) from the 4 edges to search **non-closed** islands and mark the region as invalid during traversal.
78110
* Then we traversal the graph again to find `0`, that would be closed islands.
79111

80112
```kotlin
81-
class Solution {
82-
private val invalid = 2
83-
private val directions = arrayOf(
84-
-1 to 0, 1 to 0, 0 to -1, 0 to 1)
113+
private val invalid = 2
114+
115+
fun closedIsland(grid: Array<IntArray>): Int {
116+
val m = grid.size
117+
val n = grid[0].size
85118

86-
fun closedIsland(grid: Array<IntArray>): Int {
87-
val m = grid.size
88-
val n = grid[0].size
89-
90-
for (row in 0 until m) {
91-
dfs(grid, row, 0)
92-
dfs(grid, row, n - 1)
93-
}
94-
95-
for (col in 0 until n) {
96-
dfs(grid, 0, col)
97-
dfs(grid, m - 1, col)
98-
}
99-
100-
var count = 0
101-
for (row in 0 until m) {
102-
for (col in 0 until n) {
103-
if (grid[row][col] == 0) {
104-
dfs(grid, row, col)
105-
count++
106-
}
107-
}
108-
}
109-
return count
119+
for (row in 0 until m) {
120+
dfs(grid, row, 0)
121+
dfs(grid, row, n - 1)
122+
}
123+
124+
for (col in 0 until n) {
125+
dfs(grid, 0, col)
126+
dfs(grid, m - 1, col)
110127
}
111128

112-
private fun dfs(grid: Array<IntArray>, x: Int, y: Int) {
113-
if (x in 0 until grid.size &&
114-
y in 0 until grid[0].size &&
115-
grid[x][y] == 0) {
116-
grid[x][y] = invalid
117-
118-
directions.forEach {
119-
dfs(grid, x + it.first, y + it.second)
129+
var count = 0
130+
for (row in 0 until m) {
131+
for (col in 0 until n) {
132+
if (grid[row][col] == 0) {
133+
dfs(grid, row, col)
134+
count++
120135
}
121136
}
122137
}
138+
return count
139+
}
140+
141+
private fun dfs(grid: Array<IntArray>, x: Int, y: Int) {
142+
val m = grid.size
143+
val n = grid[0].size
144+
if (x !in 0 until m || y !in 0 until n) return
145+
if (visited.contains(x to y)) return
146+
if (grid[x][y] == 1) return
147+
148+
grid[x][y] = invalid
149+
for (d in directions) {
150+
val newX = x + d[0]
151+
val newY = y + d[1]
152+
dfs(grid, newX, newY)
153+
}
123154
}
124155
```
125156

0 commit comments

Comments
 (0)