Leetcode139. Word Break
Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
Note:
The same word in the dictionary may be reused multiple times in the segmentation.
You may assume the dictionary does not contain duplicate words.
Example 1:
Input: s = "leetcode", wordDict = ["leet", "code"]
Output: true
Explanation: Return true because "leetcode" can be segmented as "leet code".
Example 2:
Input: s = "applepenapple", wordDict = ["apple", "pen"]
Output: true
Explanation: Return true because "applepenapple" can be segmented as "apple pen apple".
Note that you are allowed to reuse a dictionary word.
Example 3:
Input: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
Output: false
解法一 动态规划
思路
- 遍历字符串的所有子字符串
[i,j)
,字符串长度为n
。 - 遍历开始的索引为
i
,遍历区间[0,n)
,遍历结束的索引为j
,遍历区间[i+1,n+1)
- 若
dp[i]=True
且s[i,⋯,j)
在 wordlist 中:dp[j]=True
。
第 1 步:定义状态
dp[i]
表示 s 的前 i 位是否可以用 wordDict 中的单词表示。注意数组长度要定义为n+1
。
第 2 步:思考状态转移方程
动态规划方法的递推公式可以简略的表示为:
dp[i] = ( dp[i-1] && contains(subStr(i-1,i)) )
|| ( dp[i-2] && contains(subStr(i-2,i)) )
|| ( dp[i-3] && contains(subStr(i-3,i)) )
|| ...
第 3 步:思考初始值
初始化dp[i]
为false
,dp[0]=true
。
第 4 步:思考输出
输出dp[i]
。
|T| | | | | | | | |
0 1 2 3 4 5 6 7 8
i = 1
j = o sub = l
i = 2
j = 0 sub = le
j = 1 sub = e
i = 3
j = 0 sub = lee
j = 1 sub = ee
j = 2 sub = e
i = 4
j = 0 sub = leet && T[0] and then break, no need to check for rest
|T| | | |T| | | | |
0 1 2 3 4 5 6 7 8
i = 5
j = 0 sub = leetc
j = 1 sub = eetc
j = 2 sub = etc
j = 3 sub = tc
j = 4 sub = c
i = 6
j = 0 sub = leetco
j = 1 sub = eetco
j = 2 sub = etco
j = 3 sub = tco
j = 4 sub = co
j = 5 sub = o
i = 7
j = 0 sub = leetcod
j = 1 sub = eetcod
j = 2 sub = etcod
j = 3 sub = tcod
j = 4 sub = cod
j = 5 sub = od
j = 6 sub = d
i = 8
j = 0 sub = leetcode
j = 1 sub = eetcode
j = 2 sub = etcode
j = 3 sub = tcode
j = 4 sub = code && T[4] and then break
|T| | | |T| | | |T|
0 1 2 3 4 5 6 7 8
public boolean wordBreak(String s, List<String> wordList) {
boolean[] T = new boolean[s.length() + 1];
Set<String> set = new HashSet<>();
for (String word : wordList) {
set.add(word);
}
T[0] = true;
for (int i = 1; i <= s.length(); i++) {
for (int j = 0; j < i; j++) {
if(T[j] && set.contains(s.substring(j, i))) {
T[i] = true;
break;
}
}
}
return T[s.length()];
}
Python
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
n=len(s)
dp=[False]*(n+1)
dp[0]=True
for i in range(n):
for j in range(i+1,n+1):
if(dp[i] and (s[i:j] in wordDict)):
dp[j]=True
return dp[-1]
优化:先将wordDict
存到字典{ }中,因为s[j:i] in wordDict
的时间复杂度是O(n)。