拆分字句 | Medium | LeetCode#139. Word Break
題目敘述
- 題目難度:
Medium
- 題目描述:給定一個字串
s
,以及一個字串形成的陣列wordDict
,若s
可以被分割成一個或多個wordDict
當中的單字序列,則回傳True
Note that the same word in the dictionary may be reused multiple times in the segmentation.
解法
一開始的想法
s
中的每個字元可以 選或不選,每次形成一個子字串,就去跟 wordDict
進行比較看當前子字串是否存在於 wordDict
當中,一旦嘗試過每個子字串,則回傳結果。
我的解答
1 | class Solution { |
實際上使用了 Recursive + Memoization 的DP技巧
這裡直接講 helper
函數,首先會是撇除 dp
,會是最純粹的遞迴關係式,透過 for迴圈,來迭代 s
,透過 start
以及當前的 i
來形成不同範圍的子字串, 接著透過 std::find()
函數來查到當前子字串陣列 wordDict
範圍中是否有匹配的單字 , 如果有找到匹配單字,則遞迴呼叫 helper()
,其中也給定更新的 start
位置作為新的子字串起點。
接著就是 Memoization的部分,在 start
抵達字串終點時就回傳 true。而遞迴呼叫的結果如果存在,則對應的 dp[start]
位置設定為 1,並且在每一層遞回中,如果發現 dp[start]
並非 -1,就代表先前已經有計算過了,就直接回傳結果就好。
然而對於某個起始點 start
所切出的所有子字串,如果都沒有匹配的單字,則 dp[start] = false
執行結果
複雜度
時間複雜度
helper
函數中,在選擇不同起始點的for迴圈中,會嘗試不同的子字串,若字串長度是 $n$,則內部迴圈耗費時間也會是 $O(n)$,則遞迴深度最深為 $O(n)$,另外在字典比對中,時間複雜度會是 $O(m)$,$m$ 會是 wordDict
的大小。
因此整體時間複雜度會是 $O(n^2 \cdot m)$
空間複雜度
recursive call 深度最深為 $O(n)$,每次遞迴只會增加 start
,直到遞迴深度達到字串長度 $n$,dp
大小為 $O(n)$,用來儲存已經運算過的結果。因此整體空間複雜度一樣還是 $O(n)$。