題目:
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++; } } };