leetcode Word Search II

题目

Given a 2D board and a list of words from the dictionary, find all words in the board.

Each word must 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 in a word.

For example,
Given words = [“oath”,”pea”,”eat”,”rain”] and board =

[
[‘o’,’a’,’a’,’n’],
[‘e’,’t’,’a’,’e’],
[‘i’,’h’,’k’,’r’],
[‘i’,’f’,’l’,’v’]
]
Return [“eat”,”oath”].
Note:
You may assume that all inputs are consist of lowercase letters a-z.

click to show hint.

You would need to optimize your backtracking to pass the larger test. Could you stop backtracking earlier?

If the current candidate does not exist in all words’ prefix, you could stop backtracking immediately. What kind of data structure could answer such query efficiently? Does a hash table work? Why or why not? How about a Trie? If you would like to learn how to implement a basic trie, please work on this problem: Implement Trie (Prefix Tree) first.

题目来源:https://leetcode.com/problems/word-search-ii/

分析

有个hint就忍不住点开看,哈哈。输入为一个二维字母表和若干个单词,在二维字母表里面任一个字母开始,向某个方向(上下左右)走,匹配到给定的单词则输出。
根据提示,我们先将给定的单词建立成字典树,关于字典树的概念在这里(http://blog.csdn.net/u010902721/article/details/45749447)。然后深度优先搜索(dfs)二维字母表,在搜索过程中已经搜索到的字符串作为前序在字典树里面匹配不到就没必要再继续搜索了。

代码

代码分为两大部分,字典树的相关操作和深度优先搜索的代码。如果不熟悉字典树的话,一定要先看看字典树的概念和实现代码(http://blog.csdn.net/u010902721/article/details/45749447),字典树很简单的。

class TrieNode{//字典树的节点
public:
    int val;//标识,如果为1则表示一个单词的最后一个字符。
    TrieNode *next[26];
    TrieNode(){//构造函数中初始化节点
        this->val = 0;
        for(int i = 0; i < 26; i++)
            this->next[i] = NULL;
    }
};

class Solution {
private:
    TrieNode *root;//字典树的根节点
public:
    Solution(){
        this->root = new TrieNode;
    }
    void TrieInsert(string word){//将单词插入到字典树
        TrieNode *p = root;
        int len = word.length();
        for(int i = 0; i < len; i++){
            int d = word.at(i) - 'a';
            if(p->next[d] == NULL){
                p->next[d] = new TrieNode;
            }
            p = p->next[d];
        }
        p->val = 1;//一个单词插入结束
    }
    bool TrieSearchWord(string word){//在字典树中查找一个单词
        TrieNode *p = root;
        int len = word.length();
        for(int i = 0; i < len; i++){
            int d = word.at(i) - 'a';
            if(p->next[d] == NULL)
                return false;
            else
                p = p->next[d];
        }
        if(p->val == 1)
            return true;
        else
            return false;
    }

    //在字典树中查找一个单词前序。如果当前已经搜索到的字符串不是字典树中的某个单词的前序,肯定就不用再继续dfs了。比如当前已经搜索到的字符串为"abc",但是字典树中没有单词以"abc"开头的,那肯定就不用再继续往下dfs了。
    bool TrieSearchPre(string str){
        TrieNode *p = root;
        int len = str.length();
        for(int i = 0; i < len; i++){
            int d = str.at(i) - 'a';
            if(p->next[d] == NULL)
                return false;
            else
                p = p->next[d];
        }
        return true;
    }
    //深度优先搜索DFS
    void dfs(vector<vector<char> >&board, vector<vector<bool> > &flag, set<string> &help, string &s, int x, int y){
        int m = board.size();
        int n = board[0].size();
        int hx[] = {1,0,-1,0};//四个方向
        int hy[] = {0,1,0,-1};
        flag[x][y] = true;
        for(int i = 0; i < 4; i++){
            int xx = x + hx[i];
            int yy = y + hy[i];
            if(!(xx < 0 || xx >= m || yy < 0 || yy >= n || flag[xx][yy])){
                s.push_back(board[xx][yy]);//将当前字符加入已搜索到的字符串中
                if(TrieSearchWord(s))//字典树中有没有这个字符串
                    help.insert(s);//先放入set中,目的是去掉重复
                if(TrieSearchPre(s))//如果当前字符串作为前序在字典树中匹配不到就不需要继续dfs
                    dfs(board, flag, help, s, xx, yy);
                s.pop_back();//回溯
            }
        }
        flag[x][y] = false;
    }
    vector<string> findWords(vector<vector<char> >& board, vector<string>& words) {
        vector<string> result;
        if (board.empty() || board[0].empty() || words.empty()) return result;
        int len = words.size();
        for(int i = 0; i < len; i++)//将所给单词建立字典树
            TrieInsert(words[i]);
        int m = board.size();
        int n = board[0].size();
        vector<vector<bool> > flag(m, vector<bool>(n, false));//已访问标识
        string s;
        set<string> help;//去除重复
        for(int mi = 0; mi < m; mi++){
            for(int nj = 0; nj < n; nj++){
                s.push_back(board[mi][nj]);//将当前字符加入已搜索到的字符串中
                if(TrieSearchWord(s))//字典树中有没有这个字符串
                    help.insert(s);//先放入set中,目的是去掉重复
                if(TrieSearchPre(s))//如果当前字符串作为前序在字典树中匹配不到就不需要继续dfs
                    dfs(board, flag, help, s, mi, nj);
                s.pop_back();//回溯
            }
        }
        for(auto &word : help)
            result.push_back(word);
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值