二维数组寻找小岛

来源:互联网 发布:流程图软件visio2013 编辑:程序博客网 时间:2024/04/28 14:34

有这样一道题:


是不是看起来很复杂,昨天听了左神讲的课,他用了一个简单的算法,时间复杂度只有O(N*M)数组长度那么少!

一开始看这个题,没有什么思路,想着这个题时间复杂都肯定很高吧!直到最后才发现,卧槽,还有这种操作!!!!生气

话不多说,直接上自己的代码!

package com.zuoshen;public class Problem_02_Islands {/*给定一个二维数组,所有位置的值不是0就是1。规定每个位置可以和它上下左右位置上的值相连。有一个叫做岛的概念,定义如下:连成一片的1,如果周围都是0,那么这一片1,构成一个岛。求整张图上有多少个岛。例如:0 0 0 0 0 0 0 0 00 1 1 0 0 1 1 1 00 1 1 1 0 0 0 1 00 1 1 0 0 0 0 0 00 0 0 0 0 1 1 0 00 0 0 0 1 1 1 0 00 0 0 0 0 0 0 0 0这张图上有三个岛。0 0 0 0 0 0 0 0 00 1 1 0 1 1 1 1 00 1 1 1 1 0 0 1 00 1 1 0 0 0 0 1 00 0 0 0 0 1 1 1 00 0 0 0 1 1 1 0 00 0 0 0 0 0 0 0 0这张图上有一个岛。进阶:如果可以使用并行计算,如何来设计你的算法?*/public static int countIslands(int[][] m) {    //判断2维数组合法if (m == null || m[0] == null) {return 0;}int N = m.length;int M = m[0].length;//res标记为1的元素,统计个数。int res = 0;//如果发现为1的元素,就去感染他周围(山下左右)的元素for (int i = 0; i < N; i++) {for (int j = 0; j < M; j++) {if (m[i][j] == 1) {res++;infect(m, i, j, N, M);}}}return res;}    //感染方法public static void infect(int[][] m, int i, int j, int N, int M) {//元素下标越界或!=1退出if (i < 0 || i >= N || j < 0 || j >= M || m[i][j] != 1) {return;}m[i][j] = 2;/*小技巧:找到1之后标记为2,(随便标记一个数就行)表示这个位置元素不再会被感染。 *  为什么呢?数组在遍历时碰到1,就会将1变为2,感染周围为1的元素,周围元素继续由1变2感染各自的周围为1的元素,依此递归, 直到一个岛的元素都被感染,被0包围,无法继续感染,退出递归,res++表示找到了一个岛。 这时就要继续从开始发现1的下一个位置开始继续遍历,由于我们把感染的元素都变为了2,所以就不再去调用infect感染方法了。 直到找到一个未感染(元素都为1)的新岛。依次遍历,当数组完成一次遍历,所有的岛都会被感染,就会找到所有的岛。  时间复杂度为O(N*M).*///递归感染周围元素infect(m, i + 1, j, N, M);//上infect(m, i - 1, j, N, M);//下infect(m, i, j - 1, N, M);//作infect(m, i, j + 1, N, M);//右}public static void main(String[] args) {int[][] m1 = {  { 0, 0, 0, 0, 0, 0, 0, 0, 0 },         { 0, 1, 1, 1, 0, 1, 1, 1, 0 },         { 0, 1, 1, 1, 0, 0, 0, 1, 0 },        { 0, 1, 1, 0, 0, 0, 0, 0, 0 },         { 0, 0, 0, 0, 0, 1, 1, 0, 0 },         { 0, 0, 0, 0, 1, 1, 1, 0, 0 },        { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, };System.out.println(countIslands(m1));int[][] m2 = {  { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 1, 1, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 0, 0, 0, 1, 0 },{ 0, 1, 1, 0, 0, 0, 1, 1, 0 }, { 0, 0, 0, 0, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 1, 1, 1, 0, 0 },{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }, };System.out.println(countIslands(m2));}}

具体思路代码中注释写的很清楚,主要步骤是:
1 遍历二维数组
2 找到为1的元素标记
3递归感染周围为1的元素

是不是很爽,只有O(N*M)的时间复杂度。。。

并行计算,会使运行速度极大提高!至于如何使用并行计算,有以下思路,代码还没实现:
比如2个处理器并行计算,就把这个组分为2块,运用并查集的思想(大家可以细细研究下)和上述查找方法,并行查找。
最后在把边界公共的小岛(图中所示的红圈部分)合并就ok了。
如下图所示:



原创粉丝点击