Skip to content

Commit dfbe166

Browse files
committed
Update graph, shortest path and backtracking problem solutions
1 parent e2647da commit dfbe166

26 files changed

+664
-369
lines changed
Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,44 @@
11
## [1091. Shortest Path in Binary Matrix](https://leetcode.com/problems/shortest-path-in-binary-matrix/)
22

33
```kotlin
4+
private val directions = arrayOf(
5+
intArrayOf(-1, -1),
6+
intArrayOf(-1, 0),
7+
intArrayOf(-1, 1),
8+
intArrayOf(0, -1),
9+
intArrayOf(0, 1),
10+
intArrayOf(1, -1),
11+
intArrayOf(1, 0),
12+
intArrayOf(1, 1)
13+
)
14+
415
fun shortestPathBinaryMatrix(grid: Array<IntArray>): Int {
516
val infinite = Int.MAX_VALUE / 2
617
val n = grid.size
718
if (grid[0][0] == 1 || grid[n -1][n - 1] == 1) return -1
819

920
val distances = Array(n) { _ -> IntArray(n) { _ -> infinite }}
1021
val queue = ArrayDeque<Pair<Int, Int>>()
11-
val visited = hashSetOf<Pair<Int, Int>>()
1222
queue.add(0 to 0)
1323
visited.add(0 to 0)
1424
distances[0][0] = 1
1525
while (!queue.isEmpty()) {
1626
val node = queue.removeFirst()
1727
val x = node.first
1828
val y = node.second
19-
20-
val directions = arrayOf(
21-
intArrayOf(-1, -1),
22-
intArrayOf(-1, 0),
23-
intArrayOf(-1, 1),
24-
intArrayOf(0, -1),
25-
intArrayOf(0, 1),
26-
intArrayOf(1, -1),
27-
intArrayOf(1, 0),
28-
intArrayOf(1, 1)
29-
)
29+
if (x == n -1 && y == n - 1) return distances[x][y]
3030
directions.forEach { d ->
3131
val newX = x + d[0]
3232
val newY = y + d[1]
3333
val distance = distances[x][y] + 1
3434
if (newX in 0 until grid.size && newY in 0 until grid.size && grid[newX][newY] == 0) {
3535
if (distances[newX][newY] > distance) {
3636
distances[newX][newY] = distance
37-
}
38-
39-
if (!visited.contains(newX to newY)) {
4037
queue.addLast(newX to newY)
41-
visited.add(newX to newY)
4238
}
4339
}
4440
}
4541
}
46-
val result = distances[n - 1][n - 1]
47-
return if (result == infinite) -1 else result
42+
return -1
4843
}
4944
```

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
```kotlin
77
class Solution {
88
private val invalid = 2
9-
private val nonClosedLands = hashSetOf<Pair<Int, Int>>()
109
private val directions = arrayOf(
1110
-1 to 0, 1 to 0, 0 to -1, 0 to 1)
1211

leetcode/127.word-ladder.md

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## [127. Word Ladder](https://leetcode.com/problems/word-ladder/)
22

3-
* Build the graph: the pair words that differ by one character will be the edge.
3+
* Build the graph: the pair words that differ by one character will be the adjanct edge.
44

55
```js
66
hot:[dot,lot,]
@@ -15,45 +15,40 @@ cog:[dog,log,]
1515

1616
```kotlin
1717
fun ladderLength(beginWord: String, endWord: String, wordList: List<String>): Int {
18-
if (beginWord == endWord) return 0
19-
val queue = ArrayDeque<String>()
20-
val visited = hashSetOf<String>()
21-
val graph = mutableMapOf<String, MutableSet<String>>()
22-
graph[beginWord] = mutableSetOf<String>()
23-
for (word in wordList) {
24-
if (diff(beginWord, word) == 1) graph[beginWord]?.add(word)
25-
}
26-
for (word1 in wordList) {
27-
graph[word1] = mutableSetOf()
28-
for (word2 in wordList) {
29-
if (diff(word1, word2) == 1) graph[word1]?.add(word2)
18+
val visited = BooleanArray(wordList.size)
19+
var currentWord = beginWord
20+
val queue = ArrayDeque<Int>()
21+
for (i in 0 until wordList.size) {
22+
if (wordList[i] == beginWord) visited[i] = true
23+
else if (getDiff(currentWord, wordList[i]) == 1) {
24+
queue.addLast(i)
3025
}
3126
}
3227

33-
queue.addLast(beginWord)
34-
visited.add(beginWord)
35-
36-
var distance = 1
37-
while (!queue.isEmpty()) {
28+
// 1 for beginWord
29+
var counts = 1
30+
while (queue.isNotEmpty()) {
3831
val size = queue.size
3932
for (i in 0 until size) {
40-
val currentWord = queue.removeFirst()
41-
graph[currentWord]?.forEach { word ->
42-
if (!visited.contains(word)) {
43-
if (word == endWord) {
44-
return distance + 1
45-
}
46-
visited.add(word)
47-
queue.addLast(word)
33+
val index = queue.removeFirst()
34+
if (visited[index]) continue
35+
if (wordList[index] == endWord) return counts + 1 // +1 for endWord
36+
visited[index] = true
37+
currentWord = wordList[index]
38+
39+
for (j in 0 until wordList.size) {
40+
if (!visited[j] && getDiff(currentWord, wordList[j]) == 1) {
41+
queue.addLast(j)
4842
}
4943
}
5044
}
51-
distance++
45+
counts++
5246
}
5347
return 0
5448
}
5549

56-
private fun diff(w1: String, w2: String): Int {
50+
private fun getDiff(w1: String, w2: String): Int {
51+
if (w1 == w2) return 0
5752
var diff = 0
5853
for (i in 0 until w1.length) {
5954
if (w1[i] != w2[i]) diff++

leetcode/130.surrounded-regions.md

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## [130. Surrounded Regions](https://leetcode.com/problems/surrounded-regions/)
22

3-
3+
### Traversal
44
```kotlin
55
class Solution {
66

@@ -40,6 +40,59 @@ class Solution {
4040
}
4141
```
4242

43+
### Bounary DFS
44+
We start from four boundaries, and find the regions we don't capture, and iterate the whole board again to capture the remaining regions that really need to capture.
45+
46+
```kotlin
47+
private val directions = arrayOf(
48+
intArrayOf(-1, 0),
49+
intArrayOf(1, 0),
50+
intArrayOf(0, -1),
51+
intArrayOf(0, 1)
52+
)
53+
private val notCapture = 'A'
54+
55+
fun solve(board: Array<CharArray>): Unit {
56+
val m = board.size
57+
val n = board[0].size
58+
// First row
59+
for (c in 0 until n) {
60+
dfs(board, 0, c)
61+
}
62+
// First col
63+
for (r in 0 until m) {
64+
dfs(board, r, 0)
65+
}
66+
67+
// Last row
68+
for (c in 0 until n) {
69+
dfs(board, m - 1, c)
70+
}
71+
72+
// Last col
73+
for (r in 0 until m) {
74+
dfs(board, r, n - 1)
75+
}
76+
77+
for (i in 0 until m) {
78+
for (j in 0 until n) {
79+
// Capture
80+
if (board[i][j] == 'O') board[i][j] = 'X'
81+
// Recover
82+
else if (board[i][j] == notCapture) board[i][j] = 'O'
83+
}
84+
}
85+
}
86+
87+
private fun dfs(board: Array<CharArray>, x: Int, y: Int) {
88+
if (x < 0 || x >= board.size || y < 0 || y >= board[0].size || board[x][y] != 'O') return
89+
board[x][y] = notCapture
90+
directions.forEach { d ->
91+
dfs(board, x + d[0], y + d[1])
92+
}
93+
}
94+
```
95+
4396
### Failed Cases
4497
```js
4598
O X X

leetcode/139.word-break.md

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,81 @@ i j c a r s
2929

3030
```kotlin
3131
fun wordBreak(s: String, wordDict: List<String>): Boolean {
32-
val wordDictSet = HashSet(wordDict)
32+
val wordDictSet = HashSet<String>(wordDict)
3333
val dp = BooleanArray(s.length + 1)
34-
35-
// Base case: it's always true for empty string case
3634
dp[0] = true
37-
38-
// Iterate every states
39-
for (i in 1..s.length) {
40-
for (j in 0 until i) {
41-
val substring = s.substring(j, i)
42-
// The state of s[0:j] and the state of s[j:i]
43-
if (dp[j] && wordDictSet.contains(substring)) {
44-
dp[i] = true
35+
for (end in 1..s.length) {
36+
for (start in 0..end) {
37+
val suffix = s.substring(start, end)
38+
println("$start, $end, $suffix")
39+
if (dp[start] && wordDictSet.contains(suffix)) {
40+
dp[end] = true
4541
break
4642
}
4743
}
44+
for (i in 0 until dp.size) {
45+
print("${dp[i]},")
46+
}
47+
println()
4848
}
4949
return dp[s.length]
5050
}
5151
```
5252

53+
```js
54+
println(wordBreak("cars", listOf("car", "rs", "ca")))
55+
0, 1, c
56+
1, 1,
57+
true,false,false,false,false,
58+
0, 2, ca
59+
true,false,true,false,false,
60+
0, 3, car
61+
true,false,true,true,false,
62+
0, 4, cars
63+
1, 4, ars
64+
2, 4, rs
65+
true,false,true,true,true,
66+
true
67+
68+
println(wordBreak("cars", listOf("c", "s", "ar")))
69+
0, 1, c
70+
true,true,false,false,false,
71+
0, 2, ca
72+
1, 2, a
73+
2, 2,
74+
true,true,false,false,false,
75+
0, 3, car
76+
1, 3, ar
77+
true,true,false,true,false,
78+
0, 4, cars
79+
1, 4, ars
80+
2, 4, rs
81+
3, 4, s
82+
true,true,false,true,true,
83+
true
84+
85+
println(wordBreak("cars", listOf("s", "ar")))
86+
0, 1, c
87+
1, 1,
88+
true,false,false,false,false,
89+
0, 2, ca
90+
1, 2, a
91+
2, 2,
92+
true,false,false,false,false,
93+
0, 3, car
94+
1, 3, ar
95+
2, 3, r
96+
3, 3,
97+
true,false,false,false,false,
98+
0, 4, cars
99+
1, 4, ars
100+
2, 4, rs
101+
3, 4, s
102+
4, 4,
103+
true,false,false,false,false,
104+
false
105+
```
106+
53107
* **Time Complexity**: `O(n^2)` where `n` is the length of string.
54108
* **Space Complexity**: `O(n)` for dp table.
55109

leetcode/152.maximum-product-subarray.md

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,20 @@ Similar idea from [53. Maximum Subarray](../leetcode/53.maximum-subarray.md), bu
55

66
```kotlin
77
fun maxProduct(nums: IntArray): Int {
8-
if (nums.size == 1) return nums[0]
9-
// We store local maximum [0] and minimum [1].
10-
val dp = Array(nums.size) { _ -> IntArray(2) }
8+
val localMax = IntArray(nums.size)
9+
val localMin = IntArray(nums.size)
1110
var globalMax = nums[0]
12-
dp[0] = intArrayOf(nums[0], nums[0])
11+
localMax[0] = nums[0]
12+
localMin[0] = nums[0]
1313
for (i in 1 until nums.size) {
1414
val current = nums[i]
15-
val maxProduct = dp[i - 1][0] * current
16-
val minProduct = dp[i - 1][1] * current
15+
val productOfPreviousMax = current * localMax[i - 1]
16+
val productOfPreviousMin = current * localMin[i - 1]
1717

18-
dp[i] = intArrayOf(
19-
max(
20-
current,
21-
max(maxProduct, minProduct)
22-
),
23-
min(
24-
current,
25-
min(maxProduct, minProduct)
26-
)
27-
)
28-
globalMax = max(globalMax, dp[i][0])
18+
localMax[i] = max(max(current, productOfPreviousMax), productOfPreviousMin)
19+
localMin[i] = min(min(current, productOfPreviousMax), productOfPreviousMin)
20+
21+
globalMax = max(localMax[i], globalMax)
2922
}
3023
return globalMax
3124
}

0 commit comments

Comments
 (0)