力扣79.单词搜索
力扣刷题 8

原题,以下是题目描述:

0a300d81-3333-43d6-8946-6ffef518158f.png

题目会给一个字符类型的二维数组,一个字符序列,需要返回二维数组是否连续包含字符序列。

这题力扣难度评级是中等,我个人感觉也算中等(稍微偏下)。

思路

我们直接使用深度优先搜索,一个字符一个字符去搜索,然后按照左右上下的顺序去遍历,一旦碰到匹配成功的情况,直接结束递归,返回即可,当搜索完整个二维数组后都没搜索到,返回false。

代码一

我们看代码:

class Solution {
    public boolean exist(char[][] board, String word) {
        char c = word.charAt(0);
        int l1 = board.length;
        int l2 = board[0].length;

        for (int i = 0; i < l1; i++) {
            for (int j = 0; j < l2; j++) {
                if (board[i][j] == c) {
                    if (exist2(board, word, new StringBuilder(), i, j, word.length())) {
                        return true;
                    }
                    board[i][j] = c;
                }
            }
        }
        return false;
    }

    public boolean exist2(char[][] board, String word, StringBuilder sb, int row, int col, int n) {
        char t = board[row][col];
        sb.append(t);
        board[row][col] = 0;
        if (n == 1) {
            boolean flag = word.contentEquals(sb);
            sb.deleteCharAt(sb.length() - 1);
            return flag;
        }

        char c = word.charAt(word.length() - n + 1);
        boolean f1 = false;
        if (col + 1 < board[0].length && board[row][col + 1] == c) {
            f1 = exist2(board, word, sb, row, col + 1, n - 1);
        }

        if (!f1 && col - 1 >= 0 && board[row][col - 1] == c) {
            f1 = exist2(board, word, sb, row, col - 1, n - 1);
        }

        if (!f1 && row + 1 < board.length && board[row + 1][col] == c) {
            f1 = exist2(board, word, sb, row + 1, col, n - 1);
        }

        if (!f1 && row - 1 >= 0 && board[row - 1][col] == c) {
            f1 = exist2(board, word, sb, row - 1, col, n - 1);
        }
        sb.deleteCharAt(sb.length() - 1);
        board[row][col] = t;
        return f1;
    }

}

这里稍微优化了一下:我们只在匹配对下一个的时候才转入下一次递归。这份代码提交打败百分之60左右。其实还可以继续优化。

代码二

我们这里其实是不需要那个StringBuilder的,我们每次只有匹配到序列后才会转入下一次递归,所以消耗完n后一定是正确序列。StringBuilder的添加和删除也是需要耗时的。我们去掉StringBuilder,得到如下代码:

class Solution {
    public boolean exist(char[][] board, String word) {
        char c = word.charAt(0);
        int l1 = board.length;
        int l2 = board[0].length;

        for (int i = 0; i < l1; i++) {
            for (int j = 0; j < l2; j++) {
                if (board[i][j] == c) {
                    if (exist2(board, word, i, j, word.length())) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public boolean exist2(char[][] board, String word, int row, int col, int n) {
        char t = board[row][col];

        if (t==0){
            return false;
        }

        board[row][col] = 0;
        if (n == 1) {
            return true;
        }

        char c = word.charAt(word.length() - n + 1);
        boolean f1 = false;
        if (col + 1 < board[0].length && board[row][col + 1] == c) {
            f1 = exist2(board, word,  row, col + 1, n - 1);
        }

        if (!f1 && col - 1 >= 0 && board[row][col - 1] == c) {
            f1 = exist2(board, word,  row, col - 1, n - 1);
        }

        if (!f1 && row + 1 < board.length && board[row + 1][col] == c) {
            f1 = exist2(board, word,  row + 1, col, n - 1);
        }

        if (!f1 && row - 1 >= 0 && board[row - 1][col] == c) {
            f1 = exist2(board, word,  row - 1, col, n - 1);
        }
        board[row][col] = t;
        return f1;
    }

}

去掉了StringBuilder,提交时空打败百分之90。提升巨大。这里代码其实还有很多优化空间。详细,简单来说就是我们可以先统计board和word中的各个字符数,如果word中的某个字符大于board对应字符的数量,就直接返回false。第二点优化是看看word中第一个字符和最后一个字符的数量谁大,如果最后一个字符数量小于第一个字符数量,我们将word倒转匹配,这样可以提前跳过更多的不匹配项。引入这两个优化应该能打败百分百,感兴趣你可以自己试试。

力扣79.单词搜索
https://www.than.pw/archives/019c7982-0978-71f9-83e1-8efa644d03fa
作者
than
发布于
更新于
许可