leetcode 1020 问题优化

来源:6-7 Flood Fill 的更多优化

Meet_相识

2019-09-07

1020 号问题我先使用基于栈的深度优先遍历解决了,运行时间是30ms
然后我按照这节课的优化思路,把函数调用省去了,但是时间反而上升到39ms,找不到原因,还请老师帮忙看下

另外一个问题,这个当我尝试使用基于递归的深度优先遍历来解决的时候,感觉逻辑比基于栈的要复杂,因为要多保存一个连通分量是否是非地的信息,想问问是不是我这个思路有些狭隘了,是不是还有别的思路

优化前,30ms

public class Soluation1020 {

    private int[][] dirs = {
            {-1,0},{0,1},
            {1,0},{0,-1}
    };


    private int R;
    private int C;
    private int[][] grid;

    public int numEnclaves(int[][] A) {
        this.R = A.length;
        this.C = A[0].length;
        this.grid = A;

        int res = 0;

        for(int x=0;x<R;x++){
            for(int y=0;y<C;y++){
                if(grid[x][y] == 1){
                    res += dfs(x,y);
                }
            }
        }

        return res;
    }

    /**
     * 从x,y开始深度优先遍历,返回飞地数量
     * @param x
     * @param y
     * @return
     */
    private int dfs(int x,int y){
        LinkedList<Integer> stack = new LinkedList<>();
        int cnt = 1;
        boolean notEnclave = false;
        stack.push(x*C+y);
        grid[x][y] = 0;

        while (!stack.isEmpty()){
            int v = stack.pop();
            int curX = v / C;
            int curY = v % C;
            for (int i = 0; i < dirs.length; i++) {
                int nextX = curX + dirs[i][0];
                int nextY = curY + dirs[i][1];
                if(!inArea(nextX,nextY)){
                    notEnclave = true;
                }else if(grid[nextX][nextY] == 1){
                    cnt+=1;
                    grid[nextX][nextY] = 0;
                    stack.push(nextX * C + nextY);
                }
            }

        }

        return notEnclave ? 0 : cnt;
    }

    private boolean inArea(int x,int y){
        return x >=0 && x < R && y>=0 && y< C;
    }
}

优化后 39ms

package leetcode;

import java.util.LinkedList;

/**
 * @author gaowenfeng02
 * @desc
 * @date 2019/9/7
 */
public class Soluation1020_2 {


    private int R;
    private int C;
    private int[][] grid;

    public int numEnclaves(int[][] A) {
        this.R = A.length;
        this.C = A[0].length;
        this.grid = A;

        int res = 0;

        for(int x=0;x<R;x++){
            for(int y=0;y<C;y++){
                if(grid[x][y] == 1){
                    res += dfs(x,y);
                }
            }
        }

        return res;
    }

    /**
     * 从x,y开始深度优先遍历,返回飞地数量
     * @param x
     * @param y
     * @return
     */
    private int dfs(int x,int y){
        LinkedList<Integer> stack = new LinkedList<>();
        int cnt = 1;
        boolean notEnclave = false;
        stack.push(x*C+y);
        grid[x][y] = 0;

        while (!stack.isEmpty()){
            int v = stack.pop();
            int curX = v / C;
            int curY = v % C;

            if(curX-1 < 0){
                notEnclave = true;
            }else if(grid[curX-1][curY]==1){
                int nextX = curX - 1;
                cnt+=1;
                grid[nextX][curY] = 0;
                stack.push(nextX * C + curY);
            }

            if(curY+1 >= C){
                notEnclave = true;
            }else if(grid[curX][curY+1]==1){
                int nextY = curY + 1;
                cnt+=1;
                grid[curX][nextY] = 0;
                stack.push(curX * C + nextY);
            }

            if(curX+1 >= R){
                notEnclave = true;
            }else if(grid[curX+1][curY]==1){
                int nextX = curX + 1;
                cnt+=1;
                grid[nextX][curY] = 0;
                stack.push(nextX * C + curY);
            }

            if(curY-1 < 0){
                notEnclave = true;
            }else if(grid[curX][curY-1]==1){
                int nextY = curY - 1;
                cnt+=1;
                grid[curX][nextY] = 0;
                stack.push(curX * C + nextY);
            }
        }

        return notEnclave ? 0 : cnt;
    }
}

写回答

1回答

liuyubobobo

2019-09-07

1)

在课程的这一小节的最后,我也向同学们介绍了:我不建议同学们在这些本质是同样的算法,只是操作有所不同的优化上花过多时间。近乎没有意义。


在现代计算机上使用诸如Java这样的语言编写程序,很多时候测出的性能不完全是逻辑性能。操作系统,JVM优化等等都有影响。Leetcode上出的时间也并不准确。30ms和39ms的差别也是在太微乎其微了。只要是同一复杂度的算法,就好了。


回答你的问题:我也不知道为什么在Leetcode上,你的第二个代码反而比第一个代码慢。



2)

一个简单的方法是,对整个地图的四边进行遍历,发现陆地,就调用dfs,把陆地对应的区域变成“水”。最终,地图上剩下的所有陆地,就都属于飞地,遍历数一遍有多少就好。


继续加油!:)

0
2
Meet_相识
感谢老师,已经做出来了~只用了12ms
2019-09-07
共2条回复

玩转算法系列--图论精讲(Java版)

30+小时系统学习,bobo带你克服被图论支配的恐惧

1599 学习 · 330 问题

查看课程