问:
- 假设一个二维数组,元素只有0,1。若元素1的上下左右也是1,就当做是同一片1,称作一个岛。例如这个数组代表三片岛。如何求岛的数量
const arr = [[1,0,1,1] [1,0,0,0] [1,1,1,1] [1,1,0,1]] - 并查集结构
解:
- 遍历数组,遇到1就把它变成2,并且递归感染相邻的1。
function getIsLandNum(arr) {
let res = 0
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] === 1) {
res++
// 遇到1就感染它相邻的1
infected(i, j)
}
}
}
function infected(i, j) {
// 越界且不等于1直接返回
if (i < 0 || i >= arr.length || j < 0 || j >= arr[i].length || arr[i][j] !== 1) return
arr[i][j] = 2
infected(i - 1, j)
infected(i + 1, j)
infected(i, j - 1)
infected(i, j + 1)
}
return res
}
- 并查集
class MyNode {
constructor(val) {
this.value = val
this.father = this
}
}
class UnionFindSets {
constructor(arr) {
// node表
this.nodeMap = new Map()
// 集合大小表
this.setSizeMap = new Map()
// 遍历数组,所有数组每一项都转为node,每个node初始化都是一个集合,大小为1
for (let i of arr) {
const node = new MyNode(i)
this.nodeMap.set(i, node)
this.setSizeMap.set(node, 1)
}
}
// 两个节点的顶层节点一致则为同一集合
isSameSet(val1, val2) {
if (!(this.nodeMap.has(val1) && this.nodeMap.has(val2))) return false
return this.findLastNode(val1) === this.findLastNode(val2)
}
// 查询顶层元素
findLastNode(val) {
let node = this.nodeMap.get(val)
const stack = []
while (node.father) {
stack.push(node)
node = node.father
}
// 扁平化链表,沿途所有节点的father都指向顶层节点,避免链过长导致查询时间复杂度过高
while (stack.length) {
const pathNode = stack.pop()
pathNode.father = node
}
return node
}
unionSet(val1, val2) {
// 找到集合的顶层元素
const last1 = this.findLastNode(val1)
const last2 = this.findLastNode(val2)
if (last1 && last2 && last1 !== last2) {
// 将小的集合顶层元素的father指向大的集合顶层元素
const size1 = this.setSizeMap.get(last1)
const size2 = this.setSizeMap.get(last2)
const big = size1 > size2 ? last1 : last2
const small = big === last1 ? last2 : last1
small.father = big
this.setSizeMap.set(big, size1 + size2)
this.setSizeMap.delete(small)
}
}
}