LeetCode #139 Word Break - 刷題之旅
1 題目描述
這題簡單來說就是給定一個字串s
和一個字典wordDict
,判斷s
是否可以被空格分割成一個或多個在字典中出現的單詞。
2 解法
2.1 我的作法
但是這個為什麼說他是一個dp問題,是因為他就像背包問題一樣,s是背包,wordDict是物品,我們要看看s能不能裝下wordDict裡面的物品。如果裝錯物品可能導致裝不下。
我的想法一開始是一個用切割的方式切成兩塊,然後把所有可能的組合都存到字典裡面,最後找到可以把目前切割結果組合成s的組合。
切割成兩塊
- 例如:
applepenapple
a
+pplepenapple
ap
+plepenapple
app
+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
是5
s[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
…以此類推