forked from realpacific/algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSurroundedRegions.kt
153 lines (139 loc) · 5.28 KB
/
SurroundedRegions.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package questions
import _utils.UseCommentAsDocumentation
import utils.shouldBe
/**
* Given an `m x n` matrix board containing 'X' and 'O',
* capture all regions that are 4-directionally surrounded by 'X'.
* A region is captured by flipping all 'O's into 'X's in that surrounded region.
*
* [Source](https://leetcode.com/problems/surrounded-regions/)
*/
@UseCommentAsDocumentation
private fun solve(board: Array<CharArray>) {
val borderOs = mutableListOf<Pair<Int, Int>>()
val nonBorderOs = mutableSetOf<Pair<Int, Int>>()
val m = board.lastIndex
val n = board[0].lastIndex
for (row in 0..m) {
for (col in 0..n) {
if (board[row][col] == 'O') {
if (row == 0 || row == m || col == 0 || col == n) {
// Collect all the Os in the borders
borderOs.add(row to col)
} else {
// Collect all the inside Os
nonBorderOs.add(row to col)
}
}
}
}
traverseFromBorderOsAndRemoveConnected(board, borderOs, nonBorderOs)
}
private fun traverseFromBorderOsAndRemoveConnected(
board: Array<CharArray>,
borderOs: List<Pair<Int, Int>>,
nonBorderOs: MutableSet<Pair<Int, Int>>
) {
val connected = mutableSetOf<Pair<Int, Int>>() // collect location of Os that are connected to border Os
borderOs.forEach {
isConnectedToBorderOsOrNull(board, it, it.first + 1 to it.second, connected)
isConnectedToBorderOsOrNull(board, it, it.first to it.second + 1, connected)
isConnectedToBorderOsOrNull(board, it, it.first - 1 to it.second, connected)
isConnectedToBorderOsOrNull(board, it, it.first to it.second - 1, connected)
}
// Now that we have all the Os that are connected to the border
nonBorderOs.forEach {
if (it.first == 0 || it.first == board.lastIndex || it.second == 0 || it.second == board[0].lastIndex) {
return@forEach // ignore Os at the borders
} else if (!connected.contains(it)) {
board[it.first][it.second] = 'X' // if not connected to border, then flip it
}
}
}
private fun isConnectedToBorderOsOrNull(
board: Array<CharArray>,
src: Pair<Int, Int>,
dest: Pair<Int, Int>,
connected: MutableSet<Pair<Int, Int>>
) {
if (dest.first > board.lastIndex || dest.first < 0 || dest.second > board[0].lastIndex || dest.second < 0) {
return
}
if (connected.contains(dest)) {
return // already seen, no need to traverse
}
// These two are connected and since this is called from the bordering Os,
// so [src] & [dest] are also connected to border Os
if (board[src.first][src.second] == 'O' && board[dest.first][dest.second] == 'O') {
connected.add(dest)
isConnectedToBorderOsOrNull(board, dest, dest.first + 1 to dest.second, connected)
isConnectedToBorderOsOrNull(board, dest, dest.first to dest.second + 1, connected)
isConnectedToBorderOsOrNull(board, dest, dest.first - 1 to dest.second, connected)
isConnectedToBorderOsOrNull(board, dest, dest.first to dest.second - 1, connected)
}
}
fun main() {
run {
val board = arrayOf(
// 0 1 2 3
charArrayOf('X', 'X', 'X', 'X'), // o
charArrayOf('X', 'O', 'O', 'X'), // 1
charArrayOf('X', 'X', 'O', 'X'), // 2
charArrayOf('X', 'O', 'X', 'X') // 3
)
val expected = arrayOf(
charArrayOf('X', 'X', 'X', 'X'),
charArrayOf('X', 'X', 'X', 'X'),
charArrayOf('X', 'X', 'X', 'X'),
charArrayOf('X', 'O', 'X', 'X')
)
solve(board)
board.forEachIndexed { index, chars ->
chars shouldBe expected[index]
}
}
run {
val board = arrayOf(
charArrayOf('X', 'O', 'X', 'O', 'X', 'O'),
charArrayOf('O', 'X', 'O', 'X', 'O', 'X'),
charArrayOf('X', 'O', 'X', 'O', 'X', 'O'),
charArrayOf('O', 'X', 'O', 'X', 'O', 'X')
)
val expected =
arrayOf(
charArrayOf('X', 'O', 'X', 'O', 'X', 'O'),
charArrayOf('O', 'X', 'X', 'X', 'X', 'X'),
charArrayOf('X', 'X', 'X', 'X', 'X', 'O'),
charArrayOf('O', 'X', 'O', 'X', 'O', 'X')
)
solve(board)
board.forEachIndexed { index, chars ->
chars shouldBe expected[index]
}
}
run {
val board =
arrayOf(
charArrayOf('X', 'O', 'X', 'X'),
charArrayOf('O', 'X', 'O', 'X'),
charArrayOf('X', 'O', 'X', 'O'),
charArrayOf('O', 'X', 'O', 'X'),
charArrayOf('X', 'O', 'X', 'O'),
charArrayOf('O', 'X', 'O', 'X')
)
val expected =
arrayOf(
charArrayOf('X', 'O', 'X', 'X'),
charArrayOf('O', 'X', 'X', 'X'),
charArrayOf('X', 'X', 'X', 'O'),
charArrayOf('O', 'X', 'X', 'X'),
charArrayOf('X', 'X', 'X', 'O'),
charArrayOf('O', 'X', 'O', 'X')
)
solve(board)
board.forEachIndexed { index, chars ->
println("at index $index")
chars shouldBe expected[index]
}
}
}