zoukankan      html  css  js  c++  java
  • 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"].

    一.思路类比

          在Word Search:http://www.cnblogs.com/zengzy/p/4941110.html中说过,一个单词word在board中搜索的时间复杂度为O(m*n*m*n),如果有k个word那么时间复杂度是o(k*m*n*m*n)。那么,是否好优化一点的方式呢?我们对比Word Search2和1的不同,会发现,WS2(Word Search2)就是有k个单词,而WS1只有一个单词,所以我们希望有一种结构可以把k个单词组织起来,使得我们在k个单词中查找某个单词就像在只在一个单词中查找一样,换句话说就是,我们希望在k个单词中查找某个单词的时间成本是O(word_length)。这种结构可以借用树+哈希来完成,单词的每个字母就是树中的一个结点,而下一个字母就是该结点的下一个结点,可以用哈希表存储,而这种结构也叫字典树或键树。

    二.时间复杂度

          上文已经描述过,虽然有k个单词,但其对外表现就像只有一个单词,因此时间复杂度还是O(m*n*m*n)。

    三.空间复杂度

           在该题中,结点的子结点可以使用一个大小为26的数组表示,即26叉树:

           struct node{

                 char c;//结点值

                 bool isWord;该结点是否为某个单词的结尾

                 struct node* children[26];

           }

           树的高度为最长单词的长度,设为len,那么空间复杂度为o(26^0+26^2+...+26^len)

    四.代码,注意此处代码中存在内存泄露的问题,因为new之后析构函数并没有释放掉内存。

         

    class Tree;
    class Solution;
    class Node{
    public:
        friend class Tree;
        friend class Solution;
    private:
        char _c;
        bool _isword;
        vector<Node*> _children;
    public:
        Node(char c,bool isword=false,size_t children_size=0):_c(c),_isword(isword),_children(children_size,NULL){}
        bool getIsWord()
        {
            return _isword;
        }
    };
    
    class Tree{
    private:
        Node* _root;
    public:
        Tree(Node* root=NULL)
        {
            _root = root ;
        }
        void insert(const string& insert_str)
        {
            size_t insert_str_size = insert_str.size();
            Node* cur = _root;
            for(size_t i=0;i<insert_str_size;i++){
                if(cur->_children[insert_str[i]-'a']==NULL){
                    Node *node = new Node(insert_str[i],false,26);
                    cur->_children[insert_str[i]-'a']=node;
                    cur = node;
                }else{
                    cur = cur->_children[insert_str[i]-'a'];
                }
            }
            cur->_isword = true;
        }
        Node* getRoot()
        {
            return _root;
        }
    };
    
    class Solution {
    public:
        void dfs(vector<vector<char>>& board,vector<vector<bool>>& visited,unordered_set<string>& sets,string& str,Node* node,int row,int col,int cur_r,int cur_c)
        {
            if(cur_r<0 || cur_r>=row || cur_c<0 || cur_c>=col || visited[cur_r][cur_c]){
                return ;
            }
            visited[cur_r][cur_c] = true;
            char c = board[cur_r][cur_c] ;
            str.push_back(c);
            Node* child = node->_children[c-'a'];
            if(child != NULL){
                if(child->getIsWord())
                    sets.insert(str);
                dfs(board,visited,sets,str,child,row,col,cur_r-1,cur_c);
                dfs(board,visited,sets,str,child,row,col,cur_r,cur_c+1);
                dfs(board,visited,sets,str,child,row,col,cur_r+1,cur_c);
                dfs(board,visited,sets,str,child,row,col,cur_r,cur_c-1);
            }
            visited[cur_r][cur_c] = false;
            str.pop_back();    
        }
        
        vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
            vector<string> res;
            if(board.empty()){
                return res;
            }
            Tree root(new Node('#',false,26));
            for(size_t i=0;i<words.size();i++){
                root.insert(words[i]);
            }
            int row = board.size();
            int col = board[0].size();
            vector<vector<bool>> visited(row,vector<bool>(col,false));
            string str;
            unordered_set<string> sets;
            for(size_t i=0;i<row;i++){
                for(size_t j=0;j<col;j++){
                    dfs(board,visited,sets,str,root.getRoot(),row,col,i,j);
                }
            }
            for(auto iter = sets.begin();iter!=sets.end();iter++){
                res.push_back(*iter);
            }
            return res;
        }
    };

    写者:zengzy
    出处: http://www.cnblogs.com/zengzy
    标题有【转】字样的文章从别的地方转过来的,否则为个人学习笔记

  • 相关阅读:
    当 LAST_INSERT_ID() 带有参数时# 清空重来
    同时多次插入时
    插入失败时
    编译生成动态库
    编译生成可执行文件
    添加一个静态JAVA库
    添加一个预编译应用程序
    编译一个需要用特定key前面的应用程序
    自定义ItemDecoration设置分割线
    linux常见命令
  • 原文地址:https://www.cnblogs.com/zengzy/p/4941326.html
Copyright © 2011-2022 走看看