LeetCode79. 单词搜索 | 刷题打卡

99 阅读2分钟

LeetCode从低效到高效,点击

一、题目描述:

题目要求

给定一个二维网格和一个单词,找出该单词是否存在于网格中。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

来源:力扣(LeetCode)链接

示例

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

给定 word = "ABCCED", 返回 true
给定 word = "SEE", 返回 true
给定 word = "ABCB", 返回 false

二、思路分析:

这是一道DFS,并且需要回溯的题目,这道题恶心在可以从这个二维矩阵中找任意的点作为开始,经过这道题的暴打,我发现回溯算法最好将判断提到最前面判断,然后回溯的时候啥都不判断直接扔进去所有可能性,然后将修改回溯。

三、AC 代码:

这个写法中的has的作用非常明显,可以在发现有解的时候结束递归,但是还有优化空间

// 236ms 11mb 勉强过了
void backtrack(vector<vector<char>>& board,string &word,vector<vector<bool>> &flag,int idx,int i,int j,bool &has){


    if(i<0||has||i>=board.size()||j<0||j>=board[0].size()||flag[i][j]||board[i][j]!=word[idx]){
        return;
    }
    if(idx== word.size()-1){
        has = true;
        return;
    }
    flag[i][j] = true;

    backtrack(board,word,flag,idx+1,i+1,j,has);
    backtrack(board,word,flag,idx+1,i-1,j,has);
    backtrack(board,word,flag,idx+1,i,j+1,has);
    backtrack(board,word,flag,idx+1,i,j-1,has);

    flag[i][j] = false;
}
bool exist(vector<vector<char>>& board, string word) {
    bool has = false;
    int m = board.size(), n = board[0].size();
    vector<vector<bool>> flag(m,vector<bool>(n,false));
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){   
            backtrack(board,word,flag,0,i,j,has);
            if(has){
                return true;
            }
    }
    }
    // backtrack(board,word,flag,0);
    return has;
}

去除标记数组,利用char只是用了7个比特 用另一个比特存东西

// 236ms 11mb 勉强过了
// 184 ms	10.6MB
void backtrack(vector<vector<char>>& board,string &word,int idx,int i,int j,bool &has){


    if(i<0||has||i>=board.size()||j<0||j>=board[0].size()||board[i][j]!=word[idx]){
        return;
    }
    if(idx== word.size()-1){
        has = true;
        return;
    }
    board[i][j] ^=0x80;

    backtrack(board,word,idx+1,i+1,j,has);
    backtrack(board,word,idx+1,i-1,j,has);
    backtrack(board,word,idx+1,i,j+1,has);
    backtrack(board,word,idx+1,i,j-1,has);

    board[i][j] ^=0x80;
}
bool exist(vector<vector<char>>& board, string word) {
    bool has = false;
    int m = board.size(), n = board[0].size();
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){   
            backtrack(board,word,0,i,j,has);
            if(has){
                return true;
            }
    }
    }
    // backtrack(board,word,flag,0);
    return has;
}

四、总结:

本题中有两个重要的策略,一个是发现有解尽快停止搜索,另一个就是尽量减少标记数组的使用,在本题中利用char类型的特点将标记直接存储到了board中

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情