LeetCode #139 Word Break - 刷題之旅
1 題目描述
![]()
這題簡單來說就是給定一個字串s和一個字典wordDict,判斷s是否可以被空格分割成一個或多個在字典中出現的單詞。
2 解法
2.1 我的作法
但是這個為什麼說他是一個dp問題,是因為他就像背包問題一樣,s是背包,wordDict是物品,我們要看看s能不能裝下wordDict裡面的物品。如果裝錯物品可能導致裝不下。
我的想法一開始是一個用切割的方式切成兩塊,然後把所有可能的組合都存到字典裡面,最後找到可以把目前切割結果組合成s的組合。
切割成兩塊
- 例如:
applepenapple
a+pplepenappleap+plepenappleapp+lepenapple- …
1 | for i in range(1, n): |
如果找到一組,切成兩塊的結果都是True就找到了
- 假設
helper是一個可以判斷是否可以切割成wordDict的函數 - 關係式:
helper(word[0:i])andhelper(word[i:n])
1 | for i in range(1, n): |
終止條件
- 我們需要一個字典來存放已經切割過的結果,避免重複計算
- 如果是空字串,就是True
1 | # 如果是空字串或是在wordDict裡面,就是True |
最後
1 | class Solution: |
可見這個solution的時間複雜度是O(n^2),空間複雜度是O(n)。不太好...
2.2 優化
我們想一下,如果今天有個共同重要的是,我們需要從index=0開始找s的每一種長度的字串,是否滿足在wordDict裡面,舉例來說,我們希望dp紀錄的是,不同狀態的s是否可以被wordDict裡面的字串組合而成。
dp[apple] = True我們可以用長度來代表不同的狀態,例如可以寫成這樣dp[5] = True,這樣就可以s的前面5個字元是否可以被wordDict裡面的字串組合而成。dp[applepen] = True=dp[9] = True- 其他狀態就是False,除了
dp[0] = True,因為空字串是True
初始化 + 終止條件
1 | dp = [True] + [False] * (len(s) + 1) |
但是我們會發現一個問題,就是當找到apple的時候,我們要繼續往後比較penapple該怎麼做?如果我們知道i的位置是True,我們繼續往後比較時,我們可以直接從i的位置開始比較,這樣就可以省下很多時間。
然後我們的dictWord=['apple', 'pena','pen']這三組好了,我很喜歡用這個例子,因為如果你先選了pena,那麼可能會因為邏輯錯誤無法回傳True(apple, pen)的組。
- 我們目前已經確定
apple前五個字dp[5]=True - 然後我們會需要走到
s[i:len(w)]開始看從apple之後的文字數加上len(w)是否等於w- 就像是目前
w是pena i是5s[i:i+len(w)]是pena
- 就像是目前
- 然後我們檢查
s[i:i+len(w)]是否等於w,如果是的話,我們就可以把dp[i+len(w)]設為True,也就是目前的長度applepena是滿足的,寫成dp[9] = True - 但是在
i+len(w)的時候要注意不要超過len(s)的長度喔,否則會發生index out of range的問題。 - 最後回傳
dp[-1]就是我們的答案,也就是長度最長的那個字串是否滿足。
1 |
|
寫乾淨一點
1 | """ |
3 總結
這題我真的想了很久,一整天都在慢慢沈澱這個問題…dp真不簡單,真的很難想到怎麼用for loop的方式實現。這種類似背包問題,就是要想辦法找到前一步的最佳解,例如,在applepenapple中,如果比較到i=5時,我們要知道以當前的狀態最佳解是i=4時,所以應該考量的是i=4 + 當前的字串,是否可以更新目前得最佳解?舉例來說:
- 比較
apple的時候,更新最佳解dp[5]=True - 比較
applep的時候- 因為最佳解是
dp[5]=True - 所以我們可以從
i=4開始往後到目前的i=5考慮是否能夠更新最佳解 - 因為
s[4:5]=p不滿足任何wordDict的字串,所以dp[6]=False
- 因為最佳解是
- 比較
applepe的時候- 因為最佳解是
dp[5]=True - 所以我們可以從
i=4開始往後到目前的i=6考慮是否能夠更新最佳解 - 因為
s[4:6]=pe不滿足任何wordDict的字串,所以dp[7]=False
- 因為最佳解是
- 比較
applepen的時候- 因為最佳解是
dp[5]=True - 所以我們可以從
i=4開始往後到目前的i=8考慮是否能夠更新最佳解 - 因為
s[4:8]=pen是滿足wordDict的字串,所以dp[8]=True
- 因為最佳解是
- 比較
applepena的時候- 因為最佳解是
dp[8]=True - 所以我們可以從
i=7開始往後到目前的i=9考慮是否能夠更新最佳解 - 因為
s[7:9]=a不滿足任何wordDict的字串,所以dp[9]=False
- 因為最佳解是
- 比較
applepenap的時候- 因為最佳解是
dp[8]=True - 所以我們可以從
i=7開始往後到目前的i=10考慮是否能夠更新最佳解 - 因為
s[7:10]=ap不滿足任何wordDict的字串,所以dp[10]=False
- 因為最佳解是
- 比較
applepenapp…以此類推