1102. 得分最高的路径
-
先排序 然后并查集 。按照格子值从大到小进行遍历,没读取一个格子,就把格子进行染色,用二维数组来表示已经染色的格子集合,然后检查该格子的上下左右是否也经过染色,如果也染过色,那么将该格子加入到同一个并查集里。直到第一个格子和最后一个格子属于同一个并查集
- 初始化最大值为格子首元素的值和最后一个元素的最小值;
- 将格子中元素按值从小到大排序;
- 每次取队列尾元素染色,如果周围也被染色,就将该格子与邻近格子集合合并,更新最大值为已经染色的元素的最小值;
- 直到第一个格子和最后一个格子在一个集合中,返回最大值
/**
* @param {number[][]} A
* @return {number}
*/
var maximumMinimumPath = function(A) {
const dirctions = [[0,1],[1,0],[-1,0],[0,-1]]
const width = A.length
const height = A[0].length
const n = width * height
const djs = new DisJointSet(n)
let maxVal = Math.min(A[0][0],A[width-1][height-1])
let queue = []
for(let i=0;i<width;i++){
for(let j=0;j<height;j++){
queue.push([i,j,A[i][j]])
}
}
queue = queue.sort((a,b) => a[2] - b[2])
// 保存元素是否被染色的信息
const colorSet = A.map(item=>item.map(_=>0))
// 若是第一个格子和最后一个格子联通 则结束循环
while(!djs.isConnected(0,n-1)){
const [x,y,val] = queue.pop()
maxVal = Math.min(val,maxVal)
colorSet[x][y] = 1
dirctions.forEach(dir=>{
const nowX = dir[0] + x
const nowY = dir[1] + y
if(nowX >=0 && nowY >=0 && nowX <width && nowY<height && colorSet[nowX][nowY]===1){
// 当前格子在并查集中的index = x * height + y
// 合并相邻的元素
djs.merge(x * height + y,nowX * height + nowY)
}
})
}
return maxVal
};
class DisJointSet {
rank = []
parent = []
constructor(size){
for(let i=0;i<size;i++){
this.parent[i] = i
this.rank[i] = 1
}
}
// 找出节点p的顶点 也就是所属的集合
find(p){
if(p<0 || p>(this.parent.length-1)){
throw new Error("invalid element")
}
while(this.parent[p] !==p){
// 路径压缩 在找的过程中将树的高度剪低
this.parent[p] = this.parent[this.parent[p]]
p = this.parent[p]
}
return p
}
merge(p,q){
let pRoot = this.find(p)
let qRoot = this.find(q)
if(pRoot === qRoot){
return
}
// 基于rank的优化 将高度较小的树嫁接到高度高的树 防止在合并的过程中树的高度增加
if(this.rank[pRoot] < this.rank[qRoot]){
this.parent[pRoot] = qRoot
}else if(this.rank[pRoot] > this.rank[qRoot]){
this.parent[qRoot] = pRoot
}else{
this.parent[qRoot] = pRoot
this.rank[pRoot] ++
}
}
// 并查集大小
getsize(){
return this.parent.length
}
// 两个集合是否联通
isConnected(p,q){
return this.find(p) === this.find(q)
}
}