Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
For example, given
s = "leetcode"
,
dict = ["leet", "code"]
.
Return true because "leetcode"
can be segmented as "leet code"
.
判断给定字符串是否可以用空格分割为字典中的单词。
一、递归求解: Time Limit Exceeded
最容易想到的是递归求解了,不过也很容易想到会超时:
class Solution { public: bool wordBreak(string s, unordered_set<string> &dict) { if (dict.empty()) { return false; } if (dict.find(s) != dict.end()) { return true; } auto sz = s.size(); for (auto i = 1; i < sz; ++i) { if (wordBreak(s.substr(0,i), dict) && wordBreak(s.substr(i,sz-i), dict)) { return true; } } return false; } };
分析上面的递归解法可知有大量的重叠子问题,可用记忆法记录字符串中的子串[i,j)是否可被分割为字典中的单词。我用了一个固定大小的二维数组t,t[i][j]表示的是起始位置i,长度为j的字串是否可分割,0表示该字串还没有查询过,1表示可以分割,-1表示不可以分割。定义了一个成员变量s用来保存要查询的字符串。
class Solution { public: Solution() { memset(t, 0, sizeof(t)); for (int i = 0; i < MAX_SIZE; ++i) t[i][0] = 1; } bool wordBreak(string s, unordered_set<string> &dict) { if (dict.empty() || s.empty()) { return false; } this->s = s; return wordBreakImpl(0,s.size(),dict); } bool wordBreakImpl(int pos, int len, unordered_set<string> &dict) { if (0 == t[pos][len]) { t[pos][len] = -1; for (int i = 1; i <= len; ++i) { if (exists(pos,i,dict) && wordBreakImpl(pos+i,len-i,dict)) { t[pos][len] = 1; break; } } } return t[pos][len] == 1; } bool exists(int pos, int len, unordered_set<string> &dict) { return dict.find(s.substr(pos,len)) != dict.end(); } private: const static int MAX_SIZE = 200; int t[MAX_SIZE][MAX_SIZE]; string s; };