leetcode-200-岛屿的个数 (number of islands)-java

题目及测试

package pid200;
/*  岛屿的个数

给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

示例 1:

输入:
11110
11010
11000
00000

输出: 1

示例 2:

输入:
11000
11000
00100
00011

输出: 3




*/

import java.util.List;

public class main {
	
	public static void main(String[] args) {
		char[][] testTable = {{'1','1','0','0','0'},{'1','1','0','0','0'},
				{'0','0','1','0','0'},{'0','0','0','1','1'}};
		test(testTable);
	}
		 
	private static void test(char[][] ito) {
		Solution solution = new Solution();
		int rtn;
		long begin = System.currentTimeMillis();
		for(char[] now:ito){
			for(char nowc:now){
				System.out.print(nowc+" ");
			}
			System.out.println();
		}
		System.out.println();
		//开始时打印数组
		
		rtn= solution.numIslands(ito);//执行程序
		long end = System.currentTimeMillis();	
		
		System.out.println("rtn=" );
		System.out.print(rtn);
		
		System.out.println();
		System.out.println("耗时:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

解法1(成功,4ms,较快)

设置hasGone二维数组,使用深度优先遍历,将周围是1的都遍历到,并且设置hasGone为true。

从主方法开始,遍历过几次,就有几个岛屿(因为遍历第一个岛屿,会将岛屿所有连接的地方都设为true,那些地方不会再从主方法遍历)

	public int numIslands(char[][] grid) {
	    int rows=grid.length;
	    if(rows==0){
	    	return 0;
	    }
	    int cols=grid[0].length;
	    if(cols==0){
	    	return 0;
	    }
	    int result=0;
	    boolean[][] hasGone=new boolean[rows][cols];
	    for(int i=0;i<rows;i++){
	    	for(int j=0;j<cols;j++){
	    		// 如果为陆地而且没有被遍历过,遍历,并且岛屿数量++
	    		if(grid[i][j]=='1'&&hasGone[i][j]==false){
	    			dfsGo(i, j, rows, cols, grid, hasGone);
	    			result++;
	    		}
	    	}
	    }	
	    return result;
    }

	public void dfsGo(int i,int j,int rows,int cols,char[][] grid,boolean[][] hasGone){
		// 进入这个方法,代表这个地方可以被遍历
		hasGone[i][j]=true;
		//上
		if(j>0){
			if(grid[i][j-1]=='1'&&hasGone[i][j-1]==false){
    			dfsGo(i, j-1, rows, cols, grid, hasGone);
    		}
		}
		//下
		if(j+1<cols){
			if(grid[i][j+1]=='1'&&hasGone[i][j+1]==false){
    			dfsGo(i, j+1, rows, cols, grid, hasGone);
    		}
		}
		//左
		if(i>0){
			if(grid[i-1][j]=='1'&&hasGone[i-1][j]==false){
    			dfsGo(i-1, j, rows, cols, grid, hasGone);
    		}
		}
		//右
		if(i+1<rows){
			if(grid[i+1][j]=='1'&&hasGone[i+1][j]==false){
    			dfsGo(i+1, j, rows, cols, grid, hasGone);
    		}
		}
	}

解法2(别人的)

采用深度优先遍历,把访问过的改为‘0’,继续遍历。

思路一样,减少空间

public class 岛屿的数量 {
	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;
		int count = 0;
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				// 注意char
				if (grid[i][j] == '1') {
					count++;
					dfsSearch(grid, i, j, rows, cols);
				}
		return count++;
	}
 
	// 每遇到'1'后, 开始向四个方向 递归搜索. 搜到后变为'0',
	// 因为相邻的属于一个island. 然后开始继续找下一个'1'.
	private void dfsSearch(char[][] grid, 
			int i, int j, int rows, int cols) {
		if (i < 0 || i >= rows || j < 0 || j >= cols)
			return;
		if (grid[i][j] != '1')
			return;
		// 也可以才用一个visited数组,标记遍历过的岛屿
		grid[i][j] = '0';
		dfsSearch(grid, i + 1, j, rows, cols);
		dfsSearch(grid, i - 1, j, rows, cols);
		dfsSearch(grid, i, j + 1, rows, cols);
		dfsSearch(grid, i, j - 1, rows, cols);
 
	}
}

解法3(别人的)

并查集

 

class Solution {
  class UnionFind {
    int count; // # of connected components
    int[] parent;
    int[] rank;

    public UnionFind(char[][] grid) { // for problem 200
      count = 0;
      int m = grid.length;
      int n = grid[0].length;
      parent = new int[m * n];
      rank = new int[m * n];
      for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
          if (grid[i][j] == '1') {
            parent[i * n + j] = i * n + j;
            ++count;
          }
          rank[i * n + j] = 0;
        }
      }
    }

    public int find(int i) { // path compression
      if (parent[i] != i) parent[i] = find(parent[i]);
      return parent[i];
    }

    public void union(int x, int y) { // union with rank
      int rootx = find(x);
      int rooty = find(y);
      if (rootx != rooty) {
        if (rank[rootx] > rank[rooty]) {
          parent[rooty] = rootx;
        } else if (rank[rootx] < rank[rooty]) {
          parent[rootx] = rooty;
        } else {
          parent[rooty] = rootx; rank[rootx] += 1;
        }
        --count;
      }
    }

    public int getCount() {
      return count;
    }
  }

  public int numIslands(char[][] grid) {
    if (grid == null || grid.length == 0) {
      return 0;
    }

    int nr = grid.length;
    int nc = grid[0].length;
    int num_islands = 0;
    UnionFind uf = new UnionFind(grid);
    for (int r = 0; r < nr; ++r) {
      for (int c = 0; c < nc; ++c) {
        if (grid[r][c] == '1') {
          grid[r][c] = '0';
          if (r - 1 >= 0 && grid[r-1][c] == '1') {
            uf.union(r * nc + c, (r-1) * nc + c);
          }
          if (r + 1 < nr && grid[r+1][c] == '1') {
            uf.union(r * nc + c, (r+1) * nc + c);
          }
          if (c - 1 >= 0 && grid[r][c-1] == '1') {
            uf.union(r * nc + c, r * nc + c - 1);
          }
          if (c + 1 < nc && grid[r][c+1] == '1') {
            uf.union(r * nc + c, r * nc + c + 1);
          }
        }
      }
    }

    return uf.getCount();
  }
}

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值