• LeetCode79.word search


    问题描述:

    Given a 2D board and a word, find if the word exists in the grid.

    The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.

    For example,
    Given board =

    [
      ['A','B','C','E'],
      ['S','F','C','S'],
      ['A','D','E','E']
    ]
    

    word = "ABCCED", -> returns true,
    word = "SEE", -> returns true,
    word = "ABCB", -> returns false.

    解题思路:

    使用深度优先搜索(DFS)来进行搜索。

    需要注意的是,因为每个char只能用一次,所以我们需要设定一个visited数组来记录该路径是否已经过该点。

    注意当结果false后需要重置该失败路径的visited值为false。

    一开始我用方向来限定不会走回头路,但是这不能保证这一点不会被二次利用,所以还是用visited数组来记录更加稳妥。

    代码:

    class Solution {
        public boolean exist(char[][] board, String word) {
            // write your code here
            if(board.length == 0){
                return word.length() == 0;
            }
            if(word.length() == 0)
                return true;
            char[] wordArr = word.toCharArray();
            for(int i = 0; i < board.length; i++)
                for(int j = 0; j < board[0].length; j++){
                    boolean[][] visited = new boolean[board.length][board[0].length];
                    if(board[i][j] == wordArr[0]){
                        if(help(board, wordArr, 1, i, j, visited))
                            return true;
                    }
                }
            return false;
        }
        private boolean help(char[][] board, char[] word, int pos, int i, int j, boolean[][] visited){
            visited[i][j] = true;
            if(pos == word.length)
                return true;
            if(i-1 >= 0 && !visited[i-1][j] && board[i-1][j] == word[pos])
                if(help(board, word, pos+1, i-1, j, visited))
                    return true;
            if(i+1 < board.length && !visited[i+1][j] && board[i+1][j] == word[pos])
                if(help(board, word, pos+1, i+1, j, visited))
                    return true;
            if(j-1 >= 0 && !visited[i][j-1] && board[i][j-1] == word[pos])
                if(help(board, word, pos+1, i, j-1, visited))
                    return true;
            if(j+1 < board[0].length && !visited[i][j+1] && board[i][j+1] == word[pos])
                if(help(board, word, pos+1, i, j+1, visited))
                    return true;
            visited[i][j] = false;
            return false;
        }
    }

    但是我的解法居然运行效率特别低啊!!!!

    307ms啊啊啊啊啊

    只在3.26%啊啊啊啊啊啊我的天呐!!!

    看了一个前面51%左右的代码如下:

    class Solution {public boolean exist(char[][] board, String word) {
            if (board == null || board.length == 0) {
                return false;
            }
            int m = board.length;
            int n = board[0].length;
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    if (word.charAt(0) != board[i][j]) {
                        continue;
                    }
                    if (find(board, i, j, word, 0)) {
                        return true;
                    }
                }
            }
            return false;
        }
        
        private boolean find(char[][] board, int i, int j, String word, int start){
            if(start == word.length())
                return true;
            
            if (i < 0 || i>= board.length || 
         j < 0 || j >= board[0].length || board[i][j] != word.charAt(start)){
                return false;
         }
            
            board[i][j] = '#'; // should remember to mark it
            boolean rst = find(board, i-1, j, word, start+1) 
    || find(board, i, j-1, word, start+1) 
    || find(board, i+1, j, word, start+1) 
    || find(board, i, j+1, word, start+1);
            board[i][j] = word.charAt(start);
            return rst;
        }
    }

    突然发现我们的边界情况设定也不一样,我的是当word长度为0时返回true,而下方的时word长度为0放回false。我觉得这个边界问题可以在面试过程中问问面试官。

    下面来具体分析一下代码的不同并且寻找一下可以改进的地方。

    我使用的visited数组来判定该点是否被使用,而代码2(下面运行效率较高的)直接在矩阵里面进行更改,使用的内存比我的要小。

    同时我在dfs每一个可能的起点时都要创建一个boolean矩阵来存储,这同样耗费时间。

    所以可以通过学习代码二将访问过的位置改成一个不可能出现的字符来标志访问过。

    改进后代码如下:

    class Solution {
        public boolean exist(char[][] board, String word) {
            // write your code here
            if(board.length == 0){
                return word.length() == 0;
            }
            if(word.length() == 0)
                return true;
            char[] wordArr = word.toCharArray();
            for(int i = 0; i < board.length; i++)
                for(int j = 0; j < board[0].length; j++){
                    if(board[i][j] == wordArr[0]){
                        if(help(board, wordArr, 1, i, j))
                            return true;
                    }
                }
            return false;
        }
        private boolean help(char[][] board, char[] word, int pos, int i, int j){
            if(pos == word.length)
                return true;
                char temp = board[i][j];
            board[i][j] = '#';
            if(i-1 >= 0  && board[i-1][j] == word[pos])
                if(help(board, word, pos+1, i-1, j))
                    return true;
            if(i+1 < board.length && board[i+1][j] == word[pos])
                if(help(board, word, pos+1, i+1, j))
                    return true;
            if(j-1 >= 0 && board[i][j-1] == word[pos])
                if(help(board, word, pos+1, i, j-1))
                    return true;
            if(j+1 < board[0].length && board[i][j+1] == word[pos])
                if(help(board, word, pos+1, i, j+1))
                    return true;
            board[i][j] = temp;
            return false;
        }
    }

    代码2中是先对字符是否相等进行判断然后在进行后面的4个方向的dfs。

    而在我的实现中,在递归调用前就进行了字符相等判断,即当调用递归时一定时对可能的路径进行递归。所以我用了一个temp在暂时存储该位置的字符。

    改进后的代码有99.29%!!!!

    我觉得应该是判断后再递归比先递归在判断效率要更高一点。

    欢迎交流与讨论!

  • 相关阅读:
    Java基础教程:Java内存区域
    Java基础教程:多线程基础——线程池
    微服务实践:服务治理
    微服务实践:服务设计
    微服务实践:什么是微服务
    SpringBoot学习笔记:读取配置文件
    Java进阶教程:使用Lombok提升开发效率
    Sagas模式
    执行力:Just Do It
    执行力:Just Do It
  • 原文地址:https://www.cnblogs.com/yaoyudadudu/p/8861366.html
Copyright © 2020-2023  润新知