LeetCode Top 100 Liked Questions 200. Number of Islands (Java版; Medium)
题目描述
Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Example 1:
Input:
11110
11010
11000
00000
Output: 1
Example 2:
Input:
11000
11000
00100
00011
Output: 3
DFS, BFS
class Solution {
public int numIslands ( char [ ] [ ] grid) {
if ( grid. length== 0 || grid[ 0 ] . length== 0 ) {
return 0 ;
}
int n = grid. length, m = grid[ 0 ] . length;
boolean [ ] [ ] memo = new boolean [ n] [ m] ;
int res = 0 ;
for ( int i= 0 ; i< n; i++ ) {
for ( int j= 0 ; j< m; j++ ) {
if ( grid[ i] [ j] == '1' && memo[ i] [ j] == false ) {
res++ ;
}
bfs ( grid, memo, i, j) ;
}
}
return res;
}
private int [ ] [ ] moves = { { - 1 , 0 } , { 1 , 0 } , { 0 , - 1 } , { 0 , 1 } } ;
private void dfs ( char [ ] [ ] grid, boolean [ ] [ ] memo, int i, int j) {
if ( i< 0 || i>= grid. length|| j< 0 || j>= grid[ 0 ] . length|| memo[ i] [ j] == true || grid[ i] [ j] == '0' ) {
return ;
}
memo[ i] [ j] = true ;
for ( int [ ] move : moves) {
dfs ( grid, memo, i+ move[ 0 ] , j+ move[ 1 ] ) ;
}
}
private void bfs ( char [ ] [ ] grid, boolean [ ] [ ] memo, int i, int j) {
if ( memo[ i] [ j] == true || grid[ i] [ j] == '0' ) {
return ;
}
int n = grid. length, m = grid[ 0 ] . length;
LinkedList< Integer> queue = new LinkedList < > ( ) ;
queue. add ( i* m+ j) ;
while ( ! queue. isEmpty ( ) ) {
int cur = queue. poll ( ) ;
for ( int [ ] move : moves) {
int x = cur/ m + move[ 0 ] ;
int y = cur% m + move[ 1 ] ;
if ( x>= 0 && x< n&& y>= 0 && y< m&& memo[ x] [ y] == false && grid[ x] [ y] == '1' ) {
queue. add ( x* m+ y) ;
memo[ x] [ y] = true ;
}
}
}
}
}
第一次做; 并查集:1)元素-boss哈希表, 2)boss-人数哈希表, 3)初始化操作,collection 4)union(), 5)find(), 注意路径压缩在哪里; union()操作中, 必须通过findBoss()找某个元素的boss!; 核心:1)只需向右和向下遍历; 2)将所有的水域通过虚拟节点连接在一起
import java. util. HashMap;
import java. util. Stack;
import java. util. ArrayList;
import java. util. Collection;
class Solution {
public int numIslands ( char [ ] [ ] grid) {
if ( grid== null || grid. length== 0 || grid[ 0 ] . length== 0 )
return 0 ;
int rows = grid. length, cols = grid[ 0 ] . length;
ArrayList< Coor> al = new ArrayList < > ( ) ;
Coor[ ] [ ] coors = new Coor [ rows] [ cols] ;
for ( int i= 0 ; i< rows; i++ ) {
for ( int j= 0 ; j< cols; j++ ) {
Coor co = new Coor ( i, j) ;
al. add ( co) ;
coors[ i] [ j] = co;
}
}
Coor water = new Coor ( - 1 , - 1 ) ;
al. add ( water) ;
UnionFind uf = new UnionFind ( ) ;
uf. initialize ( al) ;
for ( int i= 0 ; i< rows; i++ ) {
for ( int j= 0 ; j< cols; j++ ) {
if ( grid[ i] [ j] == '1' ) {
if ( isValid ( grid, i, j+ 1 ) && grid[ i] [ j+ 1 ] == '1' )
uf. union ( coors[ i] [ j] , coors[ i] [ j+ 1 ] ) ;
if ( isValid ( grid, i+ 1 , j) && grid[ i+ 1 ] [ j] == '1' )
uf. union ( coors[ i] [ j] , coors[ i+ 1 ] [ j] ) ;
}
else {
uf. union ( coors[ i] [ j] , water) ;
}
}
}
return uf. count ( ) - 1 ;
}
public boolean isValid ( char [ ] [ ] grid, int i, int j) {
return i>= 0 && i< grid. length && j>= 0 && j< grid[ 0 ] . length;
}
public class UnionFind {
private HashMap< Coor, Coor> bossMap;
private HashMap< Coor, Integer> countMap;
UnionFind ( ) {
bossMap = new HashMap < > ( ) ;
countMap = new HashMap < > ( ) ;
}
public void initialize ( Collection< Coor> coors) {
bossMap. clear ( ) ;
countMap. clear ( ) ;
for ( Coor co : coors) {
bossMap. put ( co, co) ;
countMap. put ( co, 1 ) ;
}
}
public int count ( ) {
return countMap. size ( ) ;
}
public void union ( Coor a, Coor b) {
if ( a== null || b== null)
return ;
Coor aBoss = findBoss ( a) ;
Coor bBoss = findBoss ( b) ;
if ( aBoss != bBoss) {
int aCount = countMap. get ( aBoss) ;
int bCount = countMap. get ( bBoss) ;
if ( aCount<= bCount) {
bossMap. put ( aBoss, bBoss) ;
countMap. put ( bBoss, aCount + bCount) ;
countMap. remove ( aBoss) ;
}
else {
bossMap. put ( bBoss, aBoss) ;
countMap. put ( aBoss, aCount + bCount) ;
countMap. remove ( bBoss) ;
}
}
}
public boolean isSameGang ( Coor a, Coor b) {
return bossMap. get ( a) == bossMap. get ( b) ;
}
private Coor findBoss ( Coor co) {
Stack< Coor> s = new Stack < > ( ) ;
while ( co != bossMap. get ( co) ) {
s. push ( co) ;
co = bossMap. get ( co) ;
}
while ( ! s. isEmpty ( ) ) {
bossMap. put ( s. pop ( ) , co) ;
}
return co;
}
}
public class Coor {
int x;
int y;
Coor ( int x, int y) {
this . x = x;
this . y = y;
}
}
}
第一次做; 深度优先遍历(递归版)
import java. util. Stack;
class Solution {
public int numIslands ( char [ ] [ ] grid) {
if ( grid== null || grid. length== 0 || grid[ 0 ] . length== 0 )
return 0 ;
int rows= grid. length, cols= grid[ 0 ] . length;
boolean [ ] [ ] flag = new boolean [ rows] [ cols] ;
int res = 0 ;
for ( int i= 0 ; i< rows; i++ ) {
for ( int j= 0 ; j< cols; j++ ) {
res += dfs ( flag, grid, i, j) ;
}
}
return res;
}
public int dfs ( boolean [ ] [ ] flag, char [ ] [ ] grid, int i, int j) {
if ( ! isValid ( grid, i, j) )
return 0 ;
if ( flag[ i] [ j] == true )
return 0 ;
if ( grid[ i] [ j] == '0' )
return 0 ;
flag[ i] [ j] = true ;
if ( expand ( flag, grid, i - 1 , j) ) {
dfs ( flag, grid, i- 1 , j) ;
}
if ( expand ( flag, grid, i+ 1 , j) ) {
dfs ( flag, grid, i+ 1 , j) ;
}
if ( expand ( flag, grid, i, j- 1 ) ) {
dfs ( flag, grid, i, j- 1 ) ;
}
if ( expand ( flag, grid, i, j+ 1 ) ) {
dfs ( flag, grid, i, j+ 1 ) ;
}
return 1 ;
}
public boolean expand ( boolean [ ] [ ] flag, char [ ] [ ] grid, int i, int j) {
return isValid ( grid, i, j) && ! flag[ i] [ j] && grid[ i] [ j] == '1' ;
}
public boolean isValid ( char [ ] [ ] grid, int i, int j) {
return i>= 0 && i< grid. length && j>= 0 && j< grid[ 0 ] . length;
}
}
第一次做; 深度优先遍历(循环版): 循环+栈, 栈不为空时…
import java. util. Stack;
class Solution {
public int numIslands ( char [ ] [ ] grid) {
if ( grid== null || grid. length== 0 || grid[ 0 ] . length== 0 )
return 0 ;
int rows= grid. length, cols= grid[ 0 ] . length;
boolean [ ] [ ] flag = new boolean [ rows] [ cols] ;
int res = 0 ;
for ( int i= 0 ; i< rows; i++ ) {
for ( int j= 0 ; j< cols; j++ ) {
res += dfs ( flag, grid, i, j) ;
}
}
return res;
}
public int dfs ( boolean [ ] [ ] flag, char [ ] [ ] grid, int i, int j) {
if ( ! isValid ( grid, i, j) )
return 0 ;
if ( flag[ i] [ j] == true )
return 0 ;
if ( grid[ i] [ j] == '0' )
return 0 ;
Stack< Coordinate> s = new Stack < > ( ) ;
s. push ( new Coordinate ( i, j) ) ;
while ( ! s. isEmpty ( ) ) {
Coordinate curr = s. pop ( ) ;
if ( expand ( flag, grid, curr. x - 1 , curr. y) ) {
flag[ curr. x- 1 ] [ curr. y] = true ;
s. push ( curr) ;
s. push ( new Coordinate ( curr. x- 1 , curr. y) ) ;
continue ;
}
if ( expand ( flag, grid, curr. x+ 1 , curr. y) ) {
flag[ curr. x+ 1 ] [ curr. y] = true ;
s. push ( curr) ;
s. push ( new Coordinate ( curr. x+ 1 , curr. y) ) ;
continue ;
}
if ( expand ( flag, grid, curr. x, curr. y- 1 ) ) {
flag[ curr. x] [ curr. y- 1 ] = true ;
s. push ( curr) ;
s. push ( new Coordinate ( curr. x, curr. y- 1 ) ) ;
continue ;
}
if ( expand ( flag, grid, curr. x, curr. y+ 1 ) ) {
flag[ curr. x] [ curr. y+ 1 ] = true ;
s. push ( curr) ;
s. push ( new Coordinate ( curr. x, curr. y+ 1 ) ) ;
continue ;
}
}
return 1 ;
}
public boolean expand ( boolean [ ] [ ] flag, char [ ] [ ] grid, int i, int j) {
return isValid ( grid, i, j) && ! flag[ i] [ j] && grid[ i] [ j] == '1' ;
}
public boolean isValid ( char [ ] [ ] grid, int i, int j) {
return i>= 0 && i< grid. length && j>= 0 && j< grid[ 0 ] . length;
}
public class Coordinate {
int x;
int y;
Coordinate ( int x, int y) {
this . x = x;
this . y = y;
}
}
}
第一次做; 广度优先遍历: 循环+队列, 队列不为空时…
import java. util. LinkedList;
class Solution {
public int numIslands ( char [ ] [ ] grid) {
if ( grid == null || grid. length == 0 || grid[ 0 ] . length == 0 )
return 0 ;
int rows = grid. length;
int cols = grid[ 0 ] . length;
boolean [ ] [ ] flag = new boolean [ rows] [ cols] ;
int res = 0 ;
for ( int i = 0 ; i < rows; i++ ) {
for ( int j = 0 ; j < cols; j++ ) {
res += bfs ( grid, i, j, flag) ;
}
}
return res;
}
public int bfs ( char [ ] [ ] grid, int i, int j, boolean [ ] [ ] flag) {
if ( ! isCoordinateValid ( grid, i, j) )
return 0 ;
if ( flag[ i] [ j] == true )
return 0 ;
if ( grid[ i] [ j] == '0' )
return 0 ;
LinkedList< Coordinate> queue = new LinkedList < > ( ) ;
queue. add ( new Coordinate ( i, j) ) ;
flag[ i] [ j] = true ;
while ( ! queue. isEmpty ( ) ) {
Coordinate curr = queue. poll ( ) ;
if ( expand ( grid, curr. x - 1 , curr. y, flag) ) {
queue. add ( new Coordinate ( curr. x - 1 , curr. y) ) ;
flag[ curr. x - 1 ] [ curr. y] = true ;
}
if ( expand ( grid, curr. x + 1 , curr. y, flag) ) {
queue. add ( new Coordinate ( curr. x + 1 , curr. y) ) ;
flag[ curr. x + 1 ] [ curr. y] = true ;
}
if ( expand ( grid, curr. x, curr. y - 1 , flag) ) {
queue. add ( new Coordinate ( curr. x, curr. y - 1 ) ) ;
flag[ curr. x] [ curr. y - 1 ] = true ;
}
if ( expand ( grid, curr. x, curr. y + 1 , flag) ) {
queue. add ( new Coordinate ( curr. x, curr. y + 1 ) ) ;
flag[ curr. x] [ curr. y + 1 ] = true ;
}
}
return 1 ;
}
public boolean expand ( char [ ] [ ] grid, int i, int j, boolean [ ] [ ] flag) {
return isCoordinateValid ( grid, i, j) && ! flag[ i] [ j] && grid[ i] [ j] == '1' ;
}
public boolean isCoordinateValid ( char [ ] [ ] grid, int i, int j) {
int rows = grid. length;
int cols = grid[ 0 ] . length;
if ( i < 0 || i >= rows || j < 0 || j >= cols)
return false ;
return true ;
}
public class Coordinate {
int x;
int y;
Coordinate ( int x, int y) {
this . x = x;
this . y = y;
}
}
}
题解; 并查集方法, 思路分析写的非常好! 尤其是:1)只需向右和向下扩张 2)设置虚拟节点
原文链接
使用并查集解决本问题的思想很简单:
1、如果当前是“陆地”,尝试与周围合并一下;
2、如果当前是“水域”,就把所有的“水域”合并在一起,为此,我设置了一个虚拟的结点,表示“所有的水域都和这个虚拟结点是连接的”。
注意:
1、针对上面的第 1 点:如果当前是 “陆地”,尝试与周围合并一下”,此时 “周围” 并不需要像 “深度优先遍历” 和“广度优先遍历” 一样,方向是四周。
事实上,只要 “向右”、“向下” 两个方向就可以了,原因很简单,你可以在脑子里想象一个 “4 个方向” 和 “2 个方向” 的算法执行流程(或者看我下面展示的动画),
就知道 “4 个方向” 没有必要;
2、针对上面的第 2 点:由于我设置了“虚拟结点”,最后返回“岛屿个数”的时候,应该是连通分量个数 - 1,不要忘记将 “虚拟结点” 代表的 “水域” 分量去掉,
剩下的连通分量个数就是 “岛屿个数”。