每日一題,防止癡呆 = =
一、題目大意
給定一個非空字符串 s 和一個包含非空單詞列表的字典 wordDict,判定 s 是否可以被空格拆分爲一個或多個在字典中出現的單詞。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/word-break
二、題目思路以及AC代碼
思路
這道題的思路感覺挺常規的,是遞進式的。
一階段:遞歸
首先容易想到的是遞歸,我們可以直接遞歸來做,思路很清晰。就是首先用unordered_map存儲字典,然後建立遞歸函數can_break(s),其中,每個遞歸函數中,找到第一個和字典中元素匹配的元素,然後將去掉這個元素後的子串再繼續遞歸,最後就可以遍歷所有的情況,從而求得結果。
當然,這個方法在這裏會超時,畢竟有太多不必要的計算了。
二階段:動態規劃
自然,我們遞歸超時了,就可以考慮用動態規劃來進行求解。我們設 dp[i] 表示字符串的前 i 個字符,是否可以拆解。那麼我們進行遞推的時候,如果要求解 dp[i],那麼我們只需要遍歷 dp[0] ~ dp[i - 1],如果其中 dp[j] 爲 true,也就是說前 j 個字符已經是可拆的了,那麼我們只要保證 j + 1 ~ i 這個字符串在字典中,那麼前 i 個字符就都是可拆的了,這樣就有了遞推關係。時間複雜度是O(N2),相比於前一種已經減少很多了。
三階段:優化的動態規劃
到了上面的方法就是結束了嗎?當然不是,我們還能進行一些常數上的加速。我們上面需要在每次求解 dp[i] 的時候,遍歷所有的 0 ~ i - 1,然而我們可以主動一點,我們在遍歷到 i 的時候,下一步不是去遍歷 0 ~ i - 1,而是去遍歷 wordList,去求 dp[i + word.size() - 1],這樣就又可以省去一些重複遍歷 dp中元素的時間,比二階段的方法更進一步。
AC代碼
遞歸解法
class Solution {
private:
map<string, bool> wordMap;
public:
bool can_break(string s) {
if (s.empty()) return true;
int s_len = s.length();
string temp = "";
for (int i=0;i<s_len;i++) {
temp += s[i];
if (wordMap[temp] && can_break(s.substr(i + 1))) return true;
}
return false;
}
bool wordBreak(string s, vector<string>& wordDict) {
for (string word: wordDict) {
wordMap[word] = true;
}
return can_break(s);
}
};
common 動態規劃解法
class Solution {
private:
unordered_map<string, bool> wordMap;
public:
bool wordBreak(string s, vector<string>& wordDict) {
for (string word: wordDict) {
wordMap[word] = true;
}
int s_len = s.length();
bool dp[s_len + 1];
for (int i=0;i<=s_len;i++) dp[i] = false;
dp[0] = true;
for (int i=1;i<=s_len;i++) {
for (int j=0;j<i;j++) {
if (dp[j] && wordMap[s.substr(j, i - j)]) {
dp[i] = true;
break;
}
}
}
return dp[s_len];
}
};
優化動態規劃解法
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
int s_len = s.length();
bool dp[s_len + 1];
for (int i=0;i<=s_len;i++) dp[i] = false;
dp[0] = true;
for (int i=1;i<=s_len;i++) {
for (string word: wordDict) {
if (dp[i-1] && i + word.length() - 1 <= s_len && word == s.substr(i - 1, word.length())) {
dp[i + word.length() - 1] = true;
}
}
}
return dp[s_len];
}
};
如果有問題,歡迎大家指正!!!