Word Break Problems

Word Break Problems

Given a string and dictionary, check if the string can be perfectly composed from dictionary words

Solution 1: DP[i] means the substring from start to position i can be formed using dictionary words. We push forward from there.

// author: Tecker Yu
// time: 8ms
bool wordBreak(string s, vector<string>& wordDict) {
    int len = s.size();
    vector<int> dp(len+1, 0);
    unordered_set<string> dict(wordDict.begin(), wordDict.end());
    dp[0]=1;
    for(int i=1;i<=len;++i) {
        for(int j=i;j<=len;++j) {
            if (dp[i-1] && dict.find(s.substr(i-1, j-i+1))!=dict.end()) dp[j]=1;
        }
    }
    return dp[len];
}

Solution 2: dp[i] means the farthest position we can reach + 1.

bool wordBreak(string s, unordered_set<string> &dict) {
    if(dict.size()==0) return false;
        
    vector<bool> dp(s.size()+1,false);
    dp[0]=true;
        
    for(int i=1;i<=s.size();i++)
    {
		// From back to front, if we can compose it, continue to next i
        for(int j=i-1;j>=0;j--)
        {
            if(dp[j])
            {
                string word = s.substr(j,i-j);
                if(dict.find(word)!= dict.end())
                {
                    dp[i]=true;
                    break;
                }
            }
        }
    }
        
    return dp[s.size()];
}

Find all perfect combinations separated by spaces

Solution: Memoized search

class Solution {
public:
    vector<string> wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> dict(wordDict.begin(), wordDict.end());
        return break_word(s, dict);
    }
    
    vector<string> append(vector<string> & left, string& right) {
        vector<string> res;
        for(auto prefix : left) {
            res.push_back(prefix + " " + right);
        }
        return res;
    }
    
    vector<string>& break_word(string s, unordered_set<string> &dict) {
        if (mem.count(s)) return mem[s];
        
        vector<string> res;
        // Base case: s is in dictionary
        if (dict.count(s)) res.push_back(s);
        
        // Iterate through split points
        for(int i=1;i<s.size();++i) {
            string right=s.substr(i);
            if (!dict.count(right)) continue;
            string left=s.substr(0, i);
            // Recursively solve left part and right part, then add right word
            vector<string> left_res = append(break_word(left, dict), right);
            // Add to current solution
            res.insert(res.end(), left_res.begin(), left_res.end());
        }
        // Memoize the result
        mem[s]=res;
        return mem[s];
    }
private:
    unordered_map<string, vector<string> > mem;
};

#recursion #divide-and-conquer #dp