方法: 广度优先搜索
线性扫描整个二维网格,如果一个结点包含 1,则以其为根结点启动广度优先搜索。将其放入队列中,(方法一改变原来的网格:并将值设为 0 以标记访问过该结点;方法二不改变原来网格:新开一个二维数组保存是否访问该结点)。迭代地搜索队列中的每个结点,直到队列为空。
我这边做法是新开一个二维数组保存是否访问该节点。
package xxxx;
import java.util.LinkedList;
import java.util.Queue;
/**
* create by ziqiiii
*/
public class Test {
static public void main(String[] args) {
int[][] area = {
{0,1,1,0,1,0,0},
{1,0,0,1,1,1,0},
{1,1,0,0,1,1,0},
{0,1,1,0,0,1,1}
};
System.out.println(findIslandNums(area)); // 3
int[][] area2 = {
{0,1,1,0,1,0,0},
{1,0,0,1,0,1,0},
{1,1,0,0,1,1,0},
{0,1,1,0,0,1,1}
};
System.out.println(findIslandNums(area2)); //5
int[][] area3 = {{}};
System.out.println(findIslandNums(area3)); //0
int[][] area4 = {
{1,0,1,0},
{1,1,1,0},
{0,0,1,1},
{1,0,1,0},
{1,1,1,1}
};
System.out.println(findIslandNums(area4));//1
}
public static class Data{ //保存地址下标
int i;
int j;
Data(int i, int j){
this.i = i;
this.j = j;
}
}
public static int findIslandNums(int[][] area){
if(area == null){
return 0;
}
int row = area.length;
if(row == 0){
return 0;
}
int col = area[0].length;
if(col == 0){
return 0;
}
int[][] v = new int[row][col]; //v数组记录该地址是否已经被访问。不初始化,默认是0
int nums = 0;//保存岛屿个数
for(int i = 0; i < row; i++){
for(int j = 0; j< col; j++){ //遍历整个矩阵
if(v[i][j] == 0){ //没有访问过
v[i][j] = 1; //则访问该点
if(area[i][j] == 1){
nums++;
Queue<Data> queue = new LinkedList<>(); //(LinkedList实现了队列接口。)队列,进行广度优先搜索
queue.offer(new Data(i,j)); //地址入队
while(!queue.isEmpty()){
Data ele = queue.poll(); //地址出队
//向上,(可以向上,没有被访问过,且为陆地)
if(ele.i >= 1 && v[ele.i - 1][ele.j] != 1 && area[ele.i - 1][ele.j] == 1){
v[ele.i - 1][ele.j] = 1;
queue.offer(new Data(ele.i - 1,ele.j));
}
//向右
if(ele.j <= col - 2 && v[ele.i][ele.j + 1] != 1 && area[ele.i][ele.j + 1] == 1){
v[ele.i][ele.j + 1] = 1;
queue.offer(new Data(ele.i, ele.j + 1));
}
//向下
if(ele.i <= row - 2 && v[ele.i + 1][ele.j] != 1 && area[ele.i + 1][ele.j] == 1){
v[ele.i + 1][ele.j] = 1;
queue.offer(new Data(ele.i + 1, ele.j));
}
//向左
if(ele.j >= 1 && v[ele.i][ele.j - 1] != 1 && area[ele.i][ele.j - 1] == 1){
v[ele.i][ele.j - 1] = 1;
queue.offer(new Data(ele.i, ele.j - 1));
}
}
}
}
}
}
return nums;
}
}
具体AC代码: (因为上面传入的是int类型数组,需要转换一下)
class Solution {
public int numIslands(char[][] grid) {
if(grid == null){
return 0;
}
int row = grid.length;
if(row == 0){
return 0;
}
int col = grid[0].length;
if(col == 0){
return 0;
}
int[][] area = new int[row][col];
for(int i = 0; i < row; i++){
for(int j = 0; j< col; j++){
area[i][j] = grid[i][j]=='1'?1:0;
}
}
return findIslandNums(area);
}
public class Data{ //保存地址下标
int i;
int j;
Data(int i, int j){
this.i = i;
this.j = j;
}
}
public int findIslandNums(int[][] area){
if(area == null){
return 0;
}
int row = area.length;
if(row == 0){
return 0;
}
int col = area[0].length;
if(col == 0){
return 0;
}
int[][] v = new int[row][col]; //v数组记录该地址是否已经被访问。不初始化,默认是0
int nums = 0;//保存岛屿个数
for(int i = 0; i < row; i++){
for(int j = 0; j< col; j++){ //遍历整个矩阵
if(v[i][j] == 0){ //没有访问过
v[i][j] = 1; //则访问该点
if(area[i][j] == 1){
nums++;
Queue<Data> queue = new LinkedList<>(); //(LinkedList实现了队列接口。)队列,进行广度优先搜索
queue.offer(new Data(i,j)); //地址入队
while(!queue.isEmpty()){
Data ele = queue.poll(); //地址出队
//向上,(可以向上,没有被访问过,且为陆地)
if(ele.i >= 1 && v[ele.i - 1][ele.j] != 1 && area[ele.i - 1][ele.j] == 1){
v[ele.i - 1][ele.j] = 1;
queue.offer(new Data(ele.i - 1,ele.j));
}
//向右
if(ele.j <= col - 2 && v[ele.i][ele.j + 1] != 1 && area[ele.i][ele.j + 1] == 1){
v[ele.i][ele.j + 1] = 1;
queue.offer(new Data(ele.i, ele.j + 1));
}
//向下
if(ele.i <= row - 2 && v[ele.i + 1][ele.j] != 1 && area[ele.i + 1][ele.j] == 1){
v[ele.i + 1][ele.j] = 1;
queue.offer(new Data(ele.i + 1, ele.j));
}
//向左
if(ele.j >= 1 && v[ele.i][ele.j - 1] != 1 && area[ele.i][ele.j - 1] == 1){
v[ele.i][ele.j - 1] = 1;
queue.offer(new Data(ele.i, ele.j - 1));
}
}
}
}
}
}
return nums;
}
}
方法二:深度优先搜索
class Solution {
private int[][] dir = {{-1,0},{0,1},{1,0},{0,-1}};//方向
private int row,col;
private char[][] grid;
private int[][] v; //标记是否访问
public int numIslands(char[][] grid) {
this.grid = grid;
if(grid == null){
return 0;
}
row = grid.length;
if(row == 0){
return 0;
}
col = grid[0].length;
v = new int[row][col];
int num = 0;//记录岛屿数量
for(int i=0; i<row; i++){
for(int j = 0; j < col; j++){
//没有被访问过的陆地
if(v[i][j] == 0 && grid[i][j] == '1'){
num++;
dfs(i,j);
}
v[i][j] = 1; //访问
}
}
return num;
}
public void dfs(int i, int j){
v[i][j] = 1; //访问
//新下标分别为ni,nj
int ni = 0, nj = 0;
//查看它的上下左右节点,深度优先搜索
for(int k = 0; k < 4; k++){
ni = i + dir[k][0];
nj = j + dir[k][1];
if(ni >= 0 && ni < row && nj >= 0 && nj < col && v[ni][nj]==0 && grid[ni][nj] == '1'){
dfs(ni,nj);
}
}
}
}