之前刷leetcode。碰到了這道題。
一開始沒想到要用動態規劃來解。
後來看了一下答案給的**,又仔細研究了一下,發現確實是動態規劃。
中途看了很多其他人的部落格解釋,都沒把動態規劃講清楚。
所以乾脆就自己來寫乙份詳解吧。
首先,把題目貼上來
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"
.
簡單來說,就是s能不能由dict中儲存的單詞拼出來。
注意了,這裡有陷阱。不能簡單的從前往後substr遞增的檢查是否包含在dict中,否則會有問題。
比如 s=「aaaaaaa」 dict=["aaa","aaaa"]
這種例子如果用遞增的檢查,會把s檢測成 aaa aaa a ,最終返回false。而這個例子是返回true的。所以錯了。
下面開始介紹怎麼用動態規劃來講。
總的來說,動態規劃一般有2個步驟。1.把原問題劃分成若干子問題 2.已經計算過的問題可以被後面的問題利用從而減少重複計算。
該說的都說了,接下來到實際問題裡面去體會。
先貼出官網給出的標準答案
bool wordbreak(string s, unordered_set&dict)
} }return flag[s.length()];
}
簡單講一下這裡是怎麼利用動態規劃的。
首先vectorflag(s.length()+1,false);
這個容器的作用,就是前面講的2. 也就是已經計算過的問題可以被後面的問題所利用,減少重複計算。
具體怎麼做的等會再說。
這裡的第一層 i 迴圈,其實就是我們剛才講的1,也就是子問題。
你可以理解為 i 從1一直到s.length() ,分別表示從下標0開始,長度為1的子問題,長度為2的子問題,……,長度為s.length()的子問題。
而長度為s.length()的子問題的解,其實也就是原問題的解了。
現在再來解釋flag陣列。
可以理解為 flag[i]==true表示長度為i的子問題是可以成功被劃分的。
現在假設已經有 flag[i]==true,即長度為 i 的子問題是可以被劃分的。現在已經遍歷到 i+x 長度的子問題。
然後由語句:
if (flag[j] && dict.count(s.substr(j, i-j)) != 0)
遍歷到j==i時 也就是 flag[j]==flag[i] 由我剛才的假設知 ==true,即 長度為 i 的子問題是可以被劃分的
並且有s.substr(j,i-1) 這個子串包含在 dict中。
所以長度為j的子問題現在就可以被劃分成 長度為i的子問題+s.substr(j,i-1) 。
所以 長度為 j 的子問題是可以被劃分的,也就可以break了。
這樣,是不是就利用了前面 子問題i 的計算結果避免了重複計算 子問題i呢。
至此,整個動態規劃的思想就講完了。
我自己又寫了乙個遞迴版本的答案,如果你對上面的似懂非懂的話,可以參考一下我的答案。
vector*flag;
bool fun(string s, unordered_set&dict, int i)
if (i == 0 && dict.find(s.substr(i, s.length() - i)) == dict.end())
return false;
else
if (i == 0)
return true;
(*flag)[i] = true;
return fun(s.substr(0, i), dict, i-1) || fun(s, dict, i);
}bool wordbreak(string s, unordered_set&dict)
簡單給點提示,因為要遞迴,所以flag 陣列需要放在全域性變數。
整個遞迴核心部分是那個fun 函式。
最簡單的解釋就是看它的return語句。返回兩個遞迴的結果。分別表示從後往前 s.length()-i長度的這個子串是答案的解或者它不是答案的解。(有時候s的子串包含在dict中但不是答案的解,見上面的 aaa aaa a 這種分法)
是解,或者不是解,包含了所有可能的情況。因此分成了兩種子問題。再加上全域性變數flag避免重複計算。
因此滿足了動態規劃的所有步驟。得到的也是正確答案。
動態規劃問題系列 word break問題
給定乙個字串和乙個字典,在字串中新增空格來構造乙個句子,使句子中的每個單詞在字典中都存在 輸入 字串 輸出 所有可能的句子 例如 s catsanddog dict cat cats and sand dog 輸出 cats and dog和cat sand dog 將字串分割成2部分s1和s2,如...
演算法之動態規劃
一 思想 首先要了解 動態規劃 必須先知道什麼叫做 多階段決策 百科裡面對這個問題解釋的很全,我就load一段出來,大家得要好好品味,好好分析。上面圖中最後一句話就定義了動態規劃是要幹什麼的問題。二 使用規則 現在我們知道動態規劃要解決啥問題了,那麼什麼情況下我們該使用動態規劃呢?最優化原理 最優子...
演算法之動態規劃
鋼條切割問題 鋼條切割問題出現在 演算法導論 一書第204頁,作為動態規劃的例題出現,該題內容如下 serling公司購買長鋼條,將其切割為短鋼條 切割工序本身沒有成本支出。公司管理層希望知道最佳的切割方案。假定我們知道serling公司 一段長為i英吋的鋼條的 為pi i 1,2,單位為美元 鋼條...