一个错误的IF

278 阅读2分钟

事情的起因是leetcode419-甲板上的战舰,题目大概的意思是给一个数组表示海面位置,在上面放置了若干的战舰,使用‘X’表示,战舰可能是横着放可能数着放,但是战舰不相邻,让我们统计战舰的数量。

稍作思索,不难得出答案,算法的核心就是根据上一个相邻的位置判断当前位置是否存在新的战舰。

class Solution {
    public int countBattleships(char[][] board) {
        int m = board.length, n = board[0].length;
        int ret = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (i > 0 && board[i-1][j] == 'X') {
                    continue;
                }
                if (j > 0 && board[i][j-1] == 'X') {
                    continue;
                }
                if (board[i][j] == 'X') {
                    ret++;
                }
            }
        }
        return ret;
    }
}

提交后,并不意外地通过了,但是扎心的是看到执行耗时1ms,仅击败了35.20%的用户。啊?先头顶了一个大大的问号,我这算法已经是一次遍历了难道还有更好的算法吗?直觉告诉我不可能。

于是将目光转向了,for循环中寻找优化点,最后定位到了7-15行,前两个个条件判断仅在第三个if生效的时候才有意义,因为如果当前位置不是战舰,没必要进行统计与校验。

if (i > 0 && board[i-1][j] == 'X') {
    continue;
}
if (j > 0 && board[i][j-1] == 'X') {
    continue;
}
if (board[i][j] == 'X') {
    ret++;
}

于是将代码改为了,即将第三个if外移。更改后,只有当当前位置为战舰标记’X‘时才进一步判断,对于’.‘则省略了两个条件判断。

class Solution {
    public int countBattleships(char[][] board) {
        int m = board.length, n = board[0].length;
        int ret = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (board[i][j] == 'X') {
                    if (i > 0 && board[i-1][j] == 'X') {
                        continue;
                    }
                    if (j > 0 && board[i][j-1] == 'X') {
                        continue;
                    }
                    ret++;
                }
            }
        }
        return ret;
    }
}

最终提交代码耗时如下

总结

通过上面的案例,发现近更改一个条件判断,竟然能带来百分百的性能提升(从耗时来看),在编写业务代码的日子里,我是不是也遇到过类似的场景?是不是也粗心地没有理解清楚各个条件判断的层次关系?

在编写条件判断的时候,我们应该细心地梳理各个条件的层次,是否存在覆盖/包含关系。