# [139. Word Break](https://leetcode.com/problems/word-break/)
# 思路
## 思路一 DFS
此题最好想的就是用hashset记录词典以加快查找速度, 再用一个DFS即可解决. 但由于DFS里面存在很多重复计算, 所以计算复杂度很高, 亲测是会超时的.

为了避免这些重复计算, 我们可以用一个长度和字符串s等长的数组cache(初始化全为-1)来记录之前已经计算的过程.其中cache[i]=1表示s[i,i+1,...]是一个
可以拆开的字符串, 则cache[i]=0表示s[i,i+1,...]是一个拆不开的字符串.然后就可以DFS了, 我们假设s[0, 1,..., start-1]是可以拆开的, DFS函数
的内容就是判断从start开始的s的子串是否可以拆开, 那么DFS函数可以这样组织:
* 如果start到达末尾了, 那即可返回true;
* 如果cache[start]不为-1, 说明之前计算过从start开始的子串是否可以拆开, 所以直接返回cache的结果即可;
* 否则就需要进行循环递归了, 得到结果后需要对cache[start]写入合适的值.

## 思路二 动态规划
思路一使用了cache数组, 就有点动态规划的意思了. 这里我们使用一个长度为s长度加一的dp数组, 
将dp最后一个值初始化为1其他全部初始化为0, 意义和思路一中cache代表的意义一样. 那么我们就可以从后往前开始遍历并进行和思路一同样的动归了.


# C++
## 思路一
``` C++
class Solution {
private:
    bool DFS(string &s, int start, unordered_set<string>&dict, vector<int>&cache){
        if(start == s.size()) return true;
        if(cache[start] != -1) return cache[start];
        
        for(int i = start; i < s.size(); i++){
            if(dict.count(s.substr(start, i - start + 1)) && DFS(s, i + 1, dict, cache)){
                cache[start] = 1;
                return true;
            }
        }
        cache[start] = 0;
        return false;
    }
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string>dict(wordDict.begin(), wordDict.end());
        vector<int>cache(s.size(), -1);
        return DFS(s, 0, dict, cache);
    }
};
```

## 思路二
```C++
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string>dict(wordDict.begin(), wordDict.end());
        vector<int>dp(s.size() + 1, 0);
        dp[s.size()] = 1;
        for(int start = s.size(); start >= 0; start--){
            for(int i = start; i < s.size(); i++){
                if(dp[i+1] && dict.count(s.substr(start, i-start+1))){
                    dp[start] = 1;
                    break;
                }
            }
        }
        return dp[0] == 1;
    }
};
```
