Surrounded Regions
Description
Given a 2D board containing 'X'
and 'O'
(the letter O), capture all regions surrounded by 'X'
.
A region is captured by flipping all 'O'
s into 'X'
s in that surrounded region.
Example:
X X X X X O O X X X O X X O X X
After running your function, the board should be:
X X X X X X X X X X X X X O X X
Explanation:
Surrounded regions shouldn’t be on the border, which means that any 'O'
on the border of the board are not flipped to 'X'
. Any 'O'
that is not on the border and it is not connected to an 'O'
on the border will be flipped to 'X'
. Two cells are connected if they are adjacent cells connected horizontally or vertically.
Solution(javascript)
/*
* @lc app=leetcode id=130 lang=javascript
*
* [130] Surrounded Regions
*/
// @lc code=start
// /** BFS
// * @param {character[][]} board
// * @return {void} Do not return anything, modify board in-place instead.
// */
// const solve = function (board) {
// if (!board.length) {
// return
// }
// const visited = {
// }
// const key = (row, column) => `${row}-${column}`
// const bfs = (row, column) => {
// let current = [[row, column]]
// visited[key(row, column)] = true
// while (current.length > 0) {
// const next = []
// current.forEach(([row, column]) => {
// if (board[row][column + 1] === 'O' && !visited[key(row, column + 1)]) {
// visited[key(row, column + 1)] = true
// next.push([row, column + 1])
// }
// if (board[row][column - 1] === 'O' && !visited[key(row, column - 1)]) {
// visited[key(row, column - 1)] = true
// next.push([row, column - 1])
// }
// if (board[row - 1] && board[row - 1][column] === 'O' && !visited[key(row - 1, column)]) {
// visited[key(row - 1, column)] = true
// next.push([row - 1, column])
// }
// if (board[row + 1] && board[row + 1][column] === 'O' && !visited[key(row + 1, column)]) {
// visited[key(row + 1, column)] = true
// next.push([row + 1, column])
// }
// current = next
// })
// }
// }
// [0, board.length - 1].forEach((row) => {
// for (let column = 0; column < board[row].length; column++) {
// if (!visited[key(row, column)] && board[row][column] === 'O') {
// bfs(row, column)
// }
// }
// });
// [0, board[0].length - 1].forEach((column) => {
// for (let row = 0; row < board.length; row++) {
// if (!visited[key(row, column)] && board[row][column] === 'O') {
// bfs(row, column)
// }
// }
// })
// board.forEach((items, row) => {
// items.forEach((item, column) => {
// if (!visited[key(row, column)]) {
// board[row][column] = 'X'
// }
// })
// })
// }
class UnionFind {
constructor(n) {
this.parent = new Array(n).fill(0).map((val, index) => index)
this.size = new Array(n).fill(1)
this.count = n
}
root(i) {
while (this.parent[i] !== undefined && i !== this.parent[i]) {
this.parent[i] = this.parent[this.parent[i]] // Path compression
i = this.parent[i]
}
return i
}
connected(a, b) {
return this.root(a) === this.root(b)
}
union(a, b) {
const rootA = this.root(a)
const rootB = this.root(b)
if (rootA === rootB) {
return
}
if (this.parent[rootA] < this.parent[rootB]) {
this.parent[rootA] = rootB
this.size[rootB] += this.size[rootA]
} else {
this.parent[rootB] = rootA
this.size[rootA] += this.size[rootB]
}
this.count -= 1
}
getCount() {
return this.count
}
}
/** Union Find: create a dummy node
* @param {character[][]} board
* @return {void} Do not return anything, modify board in-place instead.
*/
const solve = function (board) {
if (!board.length) {
return
}
const row = board.length
const column = board[0].length
const uf = new UnionFind(row * column + 1)
const dummyNode = row * column
board.forEach((items, currentRow) => {
items.forEach((item, currentColumn) => {
const currentNode = currentRow * column + currentColumn
if (
item === 'O'
&& (
currentRow === 0
|| currentRow === row - 1
|| currentColumn === 0
|| currentColumn === column - 1)
) {
uf.union(currentNode, dummyNode)
} else if (item === 'O') {
if (board[currentRow][currentColumn + 1] === 'O') {
uf.union(currentRow * column + currentColumn + 1, currentNode)
}
if (board[currentRow][currentColumn - 1] === 'O') {
uf.union(currentRow * column + currentColumn - 1, currentNode)
}
if (board[currentRow - 1][currentColumn] === 'O') {
uf.union((currentRow - 1) * column + currentColumn, currentNode)
}
if (board[currentRow + 1][currentColumn] === 'O') {
uf.union((currentRow + 1) * column + currentColumn, currentNode)
}
}
})
})
board.forEach((items, currentRow) => {
items.forEach((item, currentColumn) => {
if (!uf.connected(currentRow * column + currentColumn, dummyNode)) {
board[currentRow][currentColumn] = 'X'
}
})
})
}