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%!!!!

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

欢迎交流与讨论!

转载于:https://www.cnblogs.com/yaoyudadudu/p/8861366.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值