leetcode:string hard系列三:word break

https://leetcode.com/problems/word-break/

https://leetcode.com/problems/word-break-ii/

class Solution {
public:
    vector<string> wordBreak(string s, unordered_set<string>& wordDict) {
		vector<string>res;
		string tmp;
		__wordBreak(s, 0, wordDict, tmp, res);
		for (int i=0;i<res.size();i++)
		{
			res[i].erase(res[i].begin());
		}
		return res;
	}
	void __wordBreak(string s, int begin, unordered_set<string>& wordDict,string tmp, vector<string>&res)
	{
		if (begin >= s.size())return;
		string substring = s.substr(begin);
		string tmp_Cur(tmp);
		if (wordDict.find(substring) != wordDict.end())
		{
			tmp_Cur += " " + substring;
			res.push_back(tmp_Cur);
		}
		if (begin == s.size() - 1)return;//只剩下一个字符串
		//接下来,分割
		for (int i=begin+1;i<s.size();i++)
		{
			tmp_Cur = tmp;
			string ssub = s.substr(begin, i - begin);
			if (wordDict.find(ssub) != wordDict.end())
			{
				tmp_Cur += " " + ssub;
				__wordBreak(s, i, wordDict, tmp_Cur, res);
			}
		}
	}
};

采用递归算法,超时,把这个字符串暴力搜索出所有的拼接情况,然后,求出最短

DP算法:

class Solution {
public:
    bool wordBreak(string s, unordered_set<string>& wordDict) {
        int n = s.size();
		vector<bool>dp(n + 1, false);
		dp[0] = true;
		for (int i=1;i<=n;i++)
		{
			for (int j=i-1;j>=0;--j)
			{
			    if(dp[j])  //从[0,j)到[j,i)的判断
			    {
			        if (wordDict.find(s.substr(j, i - j)) != wordDict.end())
				{
				    	dp[i] = true;
					break;
			        }
			    }
			
			}
		}
		return dp[n];
    }
};

动态规划,判断当前位的时候,分解成:从[0,j)到[j,i)的判断,前提是[0,j)已经满足了拼接条件

转为BFS

bool wordBreak(string s, unordered_set<string> &dict) {
    // BFS
    queue<int> BFS;
    unordered_set<int> visited;
    
    BFS.push(0);
    while(BFS.size() > 0)
    {
        int start = BFS.front();
        BFS.pop();
        if(visited.find(start) == visited.end())
        {
            visited.insert(start);
            for(int j=start; j<s.size(); j++)
            {
                string word(s, start, j-start+1);
                if(dict.find(word) != dict.end())
                {
                    BFS.push(j+1);  //BFS里面存储的意义:j->j之前的都能够break成功,因为j之前的break方式可能有很多种,所以用visted只保留其中一种
                    if(j+1 == s.size())
                        return true;
                }
            }
        }
    }
    
    return false;
}

 word break II就是word break里面所有的break可能列举出来

class Solution {
private:
    unordered_map<string, vector<string>> m; //通过map,减少迭代次数

    vector<string> combine(string word, vector<string> prev){
        for(int i=0;i<prev.size();++i){
            prev[i]+=" "+word;  //这里的prev[i]已经是rem里面的string break的结果集
        }
        return prev;
    }

public:
    vector<string> wordBreak(string s, unordered_set<string>& dict) {
        if(m.count(s)) return m[s]; //take from memory
        vector<string> result;
        if(dict.count(s)){ //a whole string is a word
            result.push_back(s);
        }
        for(int i=1;i<s.size();++i){   //就算s整个都在dict里面,但是也要尝试着继续分解
            string word=s.substr(i);
            if(dict.count(word)){  //只有当存在的时候,才会继续调用递归
                string rem=s.substr(0,i);
                vector<string> prev=combine(word,wordBreak(rem,dict));
                result.insert(result.end(),prev.begin(), prev.end());
            }
        }
        m[s]=result; //memorize
        return result;
    }
};

Stefan大神的精简版代码:

vector<string> wordBreak(string s, unordered_set<string>& wordDict) {
    unordered_map<int, vector<string>> memo {{s.size(), {""}}};
    function<vector<string>(int)> sentences = [&](int i) {
        if (!memo.count(i))  //memo[i]表示的是s.substr(i)的break结果,用map的好处就是递归收敛
            for (int j=i+1; j<=s.size(); j++)
                if (wordDict.count(s.substr(i, j-i)))
                    for (string tail : sentences(j)) //这个地方递归
                        memo[i].push_back(s.substr(i, j-i) + (tail=="" ? "" : ' ' + tail));//因为每个memo[i]都初始化为"",如果tail为空,直接忽略,
        return memo[i];};<span style="white-space:pre">						</span>                  //否则:+空格+tail
    return sentences(0);  //得到就是s.substr(0)的所有break可能
}

function是一个封装函数的容器,定义了一个 输入为int,输出为 vector<string>的function,并生成 sentences这个对象,后面lambda函数对sentences copy assignment

点赞