二维数组寻找小岛

有这样一道题:

 

 

 

 

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

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

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

public class Main {
    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了。
如下图所示:

 

posted @ 2020-02-27 18:37  何浩源  阅读(190)  评论(0)    收藏  举报
//一下两个链接最好自己保存下来,再上传到自己的博客园的“文件”选项中