lintcode_单词切分

给出一个字符串s和一个词典,判断字符串s是否可以被空格切分成一个或多个出现在字典中的单词。

您在真实的面试中是否遇到过这个题?  Yes
样例

给出

s = “lintcode”

dict = [“lint”,”code”]

返回 true 因为“lintcode”可以被空格切分成“lint code”

思路过程

直观的想法是直接遍历string,有匹配的单词就做一次切分,再去比配剩下的字符串。这样形成了下面的代码

bool wordBreak(string s, unordered_set<string> &dict) {
        // write your code here
        if(s=="")return true;
        if(dict.empty())return false;
        int be = 0;
        int i;
        for(i = 0;i<s.size();i++)
        {
            string val = s.substr(be,i-be+1);
            if(dict.find(val)!=dict.end())be = i+1;
        }
        if(be == s.size())return true;
        return false;
    }

但是这样做有情况没有考虑就是如果字典中的单词有前缀情况,例如:如果字典是这样的[“aaaa”,”aaa”]则会出错,再例如无法处理下面的情况

string target = “xyzTLcb”,dict=[“xyz”, “xyzTL,”TLcb”]

总之无论是最短匹配还是最长匹配必须要有一种回溯机制,一旦后面的匹配不正确就能回溯到上一个匹配的单词重新匹配,很容易想到递归的方法。这里采用栈的形式来保存上一个匹配的状态,代码如下:

bool wordBreak(string s, unordered_set<string> &dict){
        stack<int> beSave;
        stack<int> endSave;
        if(s=="")return true;
        if(dict.empty())return false;
        int be = 0;
        for(int i = 0;(!beSave.empty()||i<s.size())&&be<s.size();i++)
        {
            string val = s.substr(be,i-be+1);
            if(dict.find(val)!=dict.end()){
                beSave.push(be);
                endSave.push(i);
                be = i+1;
            }
            if(i==s.size()&&!beSave.empty()){
                be = beSave.top();
                i = endSave.top();
                beSave.pop();
                endSave.pop();
            }
        }
        if(be == s.size())return true;
        return false;
    }

这里时间复杂度还是比较高的,需要1957ms跑完所有case,以后再优化


点赞