题目:
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"
.
解题思路:
这是一道DP题,说实话,本人也是算法方面的菜鸟一枚,关于DP方面的题,还不太会解,没办法,只能多练习了。
这里采用DP中的两种方式实现:自顶向下和自底向上。
dp[i]表示前i个字符能否进行Wordbreak。当求解dp[i]时,可利用已经求解的dp[i-1],dp[i-2]…dp[1],dp[0]进行求解。
对于dp[n]的求解,我们可以将n个字符进行切分求解,分为前i个字符和后n-i个字符,i可以为(0,1,2,3,4…n-1)
假设i为1时,可根据dp[i]和后面的n-1个字符组成的单词是否在dict中来判断dp[n],只要i(0,1,2,3,4…n-1)其中一种
情况为真,则dp[n]为true,表示可以进行workbreak。
实现代码:
#include <iostream> #include <string> #include <vector> #include <unordered_set> using namespace std; /* 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". */ class Solution { public: bool wordBreak(string s, unordered_set<string> &dict) { if(s.size() == 0 || dict.size() == 0) return false; int len = s.size(); vector<bool> dp(len+1, false);//保存状态,dp[i]表示前i个字符是否可以进行wordBread dp[0] = true; for(int i = 1; i <= len; i++) for(int j = 0; j < i; j++) { if(dp[j] && dict.count(s.substr(j, i-j)) == 1)//对前i个字符进行切分时,只要有一种情况为true,则dp[i]=true { dp[i] = true; break; } } return dp[len]; } bool wordBreak2(string s, unordered_set<string> &dict) { if(s.size() == 0 || dict.size() == 0) return false; int len = s.size(); vector<bool> dp(len+1, false);//保存状态,dp[i]表示前i个字符是否可以进行wordBread dp[0] = true; for(int i = 0; i < len; i++) if(dp[i]) { for(int j = 1; j <= len-i; j++) if(dict.count(s.substr(i, j)) == 1) dp[i+j] = true; } return dp[len]; } //DP:自顶向下, int wordBreak3_core(string s, unordered_set<string> &dict, int *dp) { int len = s.size(); if(dp[len] >= 0) return dp[len];//如果值已经改变即不再是初始值,说明dp[len]已经求得,直接返回即可,不必再求 int isBreak; if(len == 0) isBreak = 1; else { int ret = 0; for(int i = 0; i < len; i++) { if(wordBreak3_core(s.substr(0, i), dict, dp) == 1 && dict.count(s.substr(i, len-i)) == 1) { ret = 1; break; } } isBreak = ret; } dp[len] = isBreak; return isBreak; } //DP:自顶向下, bool wordBreak3(string s, unordered_set<string> &dict) { if(s.size() == 0 || dict.size() == 0) return false; int len = s.size(); int *dp = new int[len+1];//保存状态,dp[i]表示前i个字符是否可以进行wordBread for(int i = 0; i <= len; i++) dp[i] = -1;//每个状态进行初始化 int ret = wordBreak3_core(s, dict, dp); delete [] dp; return ret; } }; int main(void) { string s("leetcode"); unordered_set<string> dict; dict.insert("leet"); dict.insert("code"); Solution solution; bool ret = solution.wordBreak3(s, dict); cout<<ret<<endl; return 0; }
网上还有通过trie树实现的,这里直接引用http://www.iteye.com/topic/1132188#2402159,就不多写了
代码如下:
class Solution { public: class Node { public: Node* next[26]; bool end; Node(): end(false) { for (int i = 0; i < 26; i++) next[i] = NULL;} void insert(string a) { Node * cur = this; for (int i = 0; i < a.size(); i++) { if (cur->next[a[i]-'a'] == NULL) { cur->next[a[i]-'a'] = new Node(); } cur = cur->next[a[i]-'a']; } cur->end = true; } ~Node () { for (int i = 0;i < 26; i++) delete next[i]; } }; bool wordBreak(string s, unordered_set<string> &dict) { Node root; for (auto it = dict.begin(); it != dict.end(); ++it) { root.insert(*it); } vector<bool> v(s.size(), false); findMatch(s, &root, 0, v); for (int i = 0; i < s.size(); i++) if (v[i]) findMatch(s, &root, i+1, v); return v[s.size() - 1]; } void findMatch(const string& s, Node* cur, int start, vector<bool> &v) { int i = start, n = s.size(); while (i < n) { if (cur->next[s[i] - 'a'] != NULL) { if (cur->next[s[i] - 'a']->end) v[i] = true; cur = cur->next[s[i] - 'a']; } else break; i++; } } };