• [LeetCode]Word Break 特里


    意甲冠军:推断字符串给定的字符串是否构成词典。

    来推断目标字符串相匹配整个字典。我们需要来推断目标字符串的每个前缀开始的下一场比赛,这需要匹配目标字符串的成功,所有前缀的枚举。


    class TrieNode{//from http://www.cnblogs.com/x1957/p/3492926.html
    public:
        TrieNode* ch[26];//char指针数组
        bool isWord;
        TrieNode():isWord(false){
            memset(ch,0,sizeof(TrieNode*)*26);
        }
        void insert(const string& ps){
            TrieNode*q=this;
            int id;
            const char* p=ps.c_str();
            while(*p){
                id=p[0]-'a';
                if(NULL==q->ch[id])
                    q->ch[id]=new TrieNode();
                q=q->ch[id];
                p++;
            }
            q->isWord=true;//是一个前缀
        }
        ~TrieNode(){
            for(int i=0;i<26;++i)
                delete ch[i];
        }
    };
    class Solution {
    public:
        bool *find;
        TrieNode *root;
        void match(string &s,int st,int ed){
            TrieNode*p=root;
            for(int i=st;i<ed;++i){
                if(p->ch[s[i]-'a']){
                    p=p->ch[s[i]-'a'];
                    if(p->isWord)find[i]=true;
                }
                else break;
            }
        }
        bool wordBreak(string s, unordered_set<string> &dict) {
            int i,n=s.size();
            unordered_set<string>::iterator bg,ed;
            root=new TrieNode();
            for(bg=dict.begin(),ed=dict.end();bg!=ed;bg++){
                root->insert(*bg);
            }
            find=new bool[n];
            memset(find,0,sizeof(bool)*n);
            //先匹配前缀
            match(s,0,n);
            //再从全部匹配的单词開始接下去匹配
            for(i=0;i<n&&find[n-1]==false;++i)
                if(find[i])
                    match(s,i+1,n);
            bool ans=find[n-1];
            delete[]find;
            delete root;
            return ans;
        }
    };


    DP版:

    一个串AB可看成两个子串A、B构成。假设A和B都匹配。则AB匹配。用dp[i]表示前缀(0,i)是否匹配,则dp[n]=dp[0,k]&dp[k+1,n],k∈[0,n]。

    这里dp[0,k]比較easy求,要推断后缀dp[k+1,n]是否在dict中。除了通过set.find(dp[k+1,n])不知还有什么办法。


    bool wordBreak(string s, unordered_set<string> &dict) {
            int i,j,n=s.size();
            bool *dp=new bool[s.size()];
    	 	memset(dp,0,sizeof(bool)*n);
    		for(i=0;i<n;++i){
    			dp[i]=dict.find(s.substr(0,i+1))!=dict.end();
    			for(j=0;j<i&&!dp[i];++j){
    				dp[i]=(dp[j]&(dict.find(s.substr(j+1,i-j))!=dict.end()));
    			}
    		}
    		bool ans=dp[n-1];
    		delete[]dp;
    		return ans;
        }


    问题2:输出全部匹配的字符串 https://oj.leetcode.com/problems/word-break-ii/

    方法:在每一个匹配的时候,针对每一个匹配的子串,记录能够匹配到该位置的子串起始位置。这样串中的一个字符就可能有多种匹配结果。

    仅仅要由后往前回溯输出全部可能就可以。


    class TrieNode{
    public:
    	TrieNode*child[26];
    	bool isWord;
    	TrieNode():isWord(false){
    		memset(child,0,sizeof(TrieNode*)*26);
    	}
    	void insert(const string &str){
    		int n=str.size(),i,id;
    		TrieNode*p=this;
    		for(i=0;i<n;++i){
    			id= str[i]-'a';
    			if(!p->child[id]) {
    				p->child[id]=new TrieNode();
    			}
    			p=p->child[id];
    		}
    		p->isWord=true;
    	}
    	~TrieNode(){
    		for(int i=0;i<26;++i){
    			delete child[i];
    			child[i]=NULL;
    		}
    	}
    };
    class Solution{
    public:
    	TrieNode*root;
    	bool *find;
    	vector<string>ans;
    	void match(string &str,int st,int ed,vector<set<int> >&pos){
    		int i,id;
    		TrieNode*p=root;
    		for(i=st;i<=ed;++i){
    			id=str[i]-'a';
    			if(p->child[id]){
    				p=p->child[id];
    				if(p->isWord){
    					find[i]=true;
    					pos[i].insert(st);
    				}
    			}
    			else break;
    		}
    	}
    	void dfs(string &str,int id,vector<set<int> >&pos,int *b,int len){
    		if(id<0){
    			string tmp;
    			for(int i=len-1;i>0;--i){
    				if(i<len-1)tmp+=" ";
    				tmp+=str.substr(b[i],b[i-1]-b[i]);
    			}
    			ans.push_back(tmp);
    			return;
    		}
    		set<int>::iterator bg=pos[id].begin(),ed=pos[id].end();
    		for(;bg!=ed;bg++){
    			b[len]=*bg;
    			dfs(str,b[len]-1,pos,b,len+1);
    		}
    	}
    	vector<string>wordBreak(string s, unordered_set<string>&dict){
    		if(s.size()==0){
    			return vector<string>();
    		}
    		unordered_set<string>::iterator bg,ed;
    		root=new TrieNode();
    		int n=s.size(),i; 
    		for(bg=dict.begin(),ed=dict.end();bg!=ed;bg++){
    			root->insert(*bg);
    		}
    		find=new bool[n];
    		vector<set<int> >pos(n);
    		int *b=new int[n+2];
    		memset(find,0,sizeof(bool)*n);
    		match(s,0,n-1,pos);
    		for(i=0;i<n;++i){
    			if(find[i])
    				match(s,i+1,n-1,pos);
    		}
    		int x=0;
    	//	cout<<pos[6].size();
    		if(find[n-1]){
    			b[x++]=n;
    			dfs(s,n-1,pos,b,x);
    		}
    		delete[] find;
    		delete[] b;
    		return ans;
    	}
    };



    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    uva 1606 极角扫描
    Codeforces Round #304 (Div. 2) 题解
    Codeforces Round #306 (Div. 2) 题解
    Codeforces Round #299 (Div. 2) 题解
    树链剖分专题
    bzoj 1036: [ZJOI2008]树的统计Count
    bzoj 1007: [HNOI2008]水平可见直线
    bzoj 1003: [ZJOI2006]物流运输trans
    Codeforces Round #301 (Div. 2) 题解
    bzoj 1026: [SCOI2009]windy数
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4842677.html
Copyright © 2020-2023  润新知