这个题,我看助教写的难理解,之前记得写过大圣说的一个找单词的跟着差不错,然后我看了题解 找到了一个根助教思路一样的,但是觉得人家的代码更容易理解,重要的是执行争取了,代码如下
方法一 并查集
并查集能够看懂,但是解体思路看不懂
class UnionFind {
constructor(n) { //构造一个节点数为n的集合
this.count = n //并查集总数
this.parent = new Array(n)
this.size = new Array(n) // size数组记录着每棵树的重量
for (let i = 0; i < n; i++) {
this.parent[i] = i; // 自己是自己的parent
this.size[i] = 1; //每个集合上节点的数量
}
}
union(p, q) { //连通结点p和结点q, p和q都是索引
let rootP = this.find(p);
let rootQ = this.find(q);
if (rootP === rootQ) return
// 元素数量小的接到数量多的下面,这样比较平衡
if (this.size[rootP] > this.size[rootQ]) {
this.parent[rootQ] = rootP;
this.size[rootP] += this.size[rootQ];
} else {
this.parent[rootP] = rootQ;
this.size[rootQ] += this.size[rootP];
}
this.count--;
}
isConnected(p, q) { //判断p,q是否连通
return this.find(p) === this.find(q)
}
find(x) { //找到x结点的root
while (this.parent[x] != x) {
// 进行路径压缩
this.parent[x] = this.parent[this.parent[x]];
x = this.parent[x];
}
return x;
}
getCount() { //返回子集个数
return this.count;
}
}
var numIslands = function (grid) {
let m = grid.length
if (m === 0) return 0
let n = grid[0].length
const dummy = -1
const dirs = [[1, 0], [0, 1]]//方向数组 向右 向下
const uf = new UnionFind(m * n)
for (let x = 0; x < m; x++) {
for (let y = 0; y < n; y++)
if (grid[x][y] === '0') {//如果网格是0,则和dummy合并
uf.union(n * x + y, dummy)
}
else if (grid[x][y] === '1') {//如果网格是1,则向右 向下尝试
for (let d of dirs) {
let r = x + d[0]
let c = y + d[1]
if (r >= m || c >= n) continue //坐标合法性
if (grid[r][c] === '1') { //当前网格的右边 下面如果是1,则和当前网格合并
uf.union(n * x + y, n * r + c)
}
}
}
}
return uf.getCount() //返回并查集的个数减一就行
};
方法二 dfs 思路:循环网格,深度优先遍历每个坐标的四周,注意坐标不要越界,遇到陆地加1,并沉没四周的陆地,这样就不会重复计算
复杂度:时间复杂度O(mn), m和n是行数和列数。空间复杂度是O(mn),最坏的情况下所有网格都需要递归,递归栈深度达到m * n
/**
* @param {character[][]} grid
* @return {number}
*/
const numIslands = (grid) => {
let count = 0
for (let i = 0; i < grid.length; i++) {
for (let j = 0; j < grid[0].length; j++) {//循环网格
if (grid[i][j] === '1') {//如果为陆地,count++,
count++
turnZero(i, j, grid)
}
}
}
return count
}
function turnZero(i, j, grid) {//沉没四周的陆地
if (i < 0 || i >= grid.length || j < 0
|| j >= grid[0].length || grid[i][j] === '0') return //检查坐标的合法性
grid[i][j] = '0'//让四周的陆地变为海水
turnZero(i, j + 1, grid)
turnZero(i, j - 1, grid)
turnZero(i + 1, j, grid)
turnZero(i - 1, j, grid)
}
题外话,这道题我刚开始按照助教讲解敲的,也是对的,就是第一次的时候findSet里面,this.findSet()小括号写成大括号了 一直不对
findSet(index) {
if (this.parent[index] !== index) {
//
this.parent[index] = this.findSet(this.parent[index])
}
return this.parent[index];
}
/*
* @lc app=leetcode.cn id=200 lang=javascript
*
* [200] 岛屿数量
*/
// @lc code=start
/**
* @param {character[][]} grid
* @return {number}
*/
let count;
var numIslands = function (grid) {
let m = grid.length;
let n = grid[0].length;
let uf = new UnionFind(m * n)
// 对二维数组进行搜索
count = 0;
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (grid[i][j] === '1') {
count++;
}
}
}
// 搜索 上下左右四方向
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (grid[i][j] === '1') {
if (i - 1 >= 0 && grid[i - 1][j] === '1') {
uf.unite(i * n + j, (i - 1) * n + j)
}
if (i + 1 < m && grid[i + 1][j] === '1') {
uf.unite(i * n + j, (i + 1) * n + j)
}
if (j - 1 >= 0 && grid[i][j - 1] === '1') {
uf.unite(i * n + j, i * n + j - 1)
}
if (j + 1 < n && grid[i][j + 1] === '1') {
uf.unite(i * n + j, i * n + j + 1)
}
}
}
}
return count
};
class UnionFind {
constructor(n) {
this.parent = new Array(n).fill(0).map((v, i) => i);
this.rank = new Array(n).fill(1);
this.setCount = n;
}
findSet(index) {
if (this.parent[index] !== index) {
//
this.parent[index] = this.findSet(this.parent[index])
}
return this.parent[index];
}
unite(index1, index2) {
let root1 = this.findSet(index1), root2 = this.findSet(index2);
if (root1 !== root2) {
// ---------- start-------
/* // 这一步不离基
// 就是把节点少的往节点多的合并
// 方法一
if (root1 < root2) {
[root1, root2] = [root2, root1]
}
// 合并 这一步明白
this.parent[root2] = root1;
// 计算合并的疏朗
this.rank[root1] += this.rank[root2]; */
//方法二 下面这种方法也是对的-----
// 元素数量小的接到数量多的下面,这样比较平衡
if (this.rank[root1] > this.rank[root2]) {
this.parent[root2] = root1;
this.rank[root1] += this.rank[root2];
} else {
this.parent[root1] = root2;
this.rank[root2] += this.rank[root1];
}
// ---------- end------
//合并以后减少
this.setCount--;
}
}
getCount() {
return this.setCount;
}
connected() {
let root1 = this.findSet(index1), root2 = this.findSet(index2);
return root1 === root2;
}
}
// @lc code=end