把四边的 O 联通到一个特殊父节点上,本代码是 empthNodeParent,这样再去数据的里面遍历,如果是 O 就联通,那么四边的O就联通在 empthNodeParent 上,符合条件的里面的O就联通在他们自己的一个节点上,最后遍历整个数组里面的O,如果不和empthNodeParent联通,那么他就应该变成X
// TypeScript 并查集实现
class UnionFind{
// 可直接 实例.count 获取
count: number
parent: number[]
constructor(n:number){
this.count=n
this.parent=Array.from({length:n},(a,b)=>b)
}
find(x:number):number{
if(this.parent[x]!==x){
this.parent[x]=this.find(this.parent[x])
}
return this.parent[x]
}
union(p:number,q:number){
let rootP=this.find(p)
let rootQ=this.find(q)
if(rootP===rootQ){
return
}
this.parent[rootQ]=rootP
}
connected(p:number,q:number){
let rootP=this.find(p)
let rootQ=this.find(q)
return rootP === rootQ
}
getCount(){
return this.count
}
}
// 二维位置压缩到一维存储
function getId(x:number,y:number,n:number){
return x*n+y
}
/**
Do not return anything, modify board in-place instead.
*/
function solve(board: string[][]): void {
let m=board.length
let n=board[0].length
let uf=new UnionFind(m*n+1)
let empthNodeParent = m*n
// 四个边的 O 要联通到 empthNodeParent 节点,代表特殊的 O
for(let i=0;i<m;i++){
if(board[i][0]==='O'){
uf.union(getId(i,0,n),empthNodeParent)
}
if(board[i][n-1]==='O'){
uf.union(getId(i,n-1,n),empthNodeParent)
}
}
for(let i=0;i<n;i++){
if(board[0][i]==='O'){
uf.union(getId(0,i,n),empthNodeParent)
}
if(board[m-1][i]==='O'){
uf.union(getId(m-1,i,n),empthNodeParent)
}
}
let direction = [[-1,0],[0,1],[1,0],[0,-1]]
for(let i=1;i<m-1;i++){
for(let j=1;j<n-1;j++){
if(board[i][j]==='O'){
for(let k=0;k<direction.length;k++){
let tx=i+direction[k][0]
let ty=j+direction[k][1]
if(board[tx][ty]==='O'){
uf.union(getId(i,j,n),getId(tx,ty,n))
}
}
}
}
}
for(let i=0;i<m;i++){
for(let j=0;j<n;j++){
if(board[i][j]==='O'&&!uf.connected(getId(i,j,n),empthNodeParent)){
board[i][j]='X'
}
}
}
};