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
思路:这个问题真的和背包问题很像,所以直觉上感觉是DP,但是没有直接找到转换成dp的表达式。。。后来看答案,发现自己dp方面还得加强。。。
下面转自:https://leetcode.com/problems/word-break/discuss/134107/Clear-DP-Thinking-Process-with-Java-Code-Beats-75
The problem is to check if s[0..slen-1] can be segmented into dictionary words,
if we define STATE dp[i] as s[0, i-1] can be segmented into dictionary words, the AIM STATE is dp[slen].
STATE TRANSFER as below:
if we stand at dp[i],
dp[i] is true if there exists a j (0 <= j < i) such that
(dp[j] && wordDict.contains(s.substring(j, i)));
In this case, dp[0] does not make sense, however, we should take care of its value in case it affects the values generated from it. dp[0] && wordDict.contains(s.substring(0, i)) should make dp[i] true, so we set dp[0] true in default.
The Bottom-up DP is as below:
public boolean wordBreak(String s, List<String> wordDict) {
boolean[] dp = new boolean[s.length() + 1];
dp[0] = true;
for (int i = 1; i <= s.length(); i++) {
for (int j = 0; j < i; j++) {
if (dp[j] && wordDict.contains(s.substring(j, i))) {
dp[i] = true;
break;
}
}
}
return dp[s.length()];
}