题目:
139. 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
解法:
class Solution {
private final Set<String> wordSet = new HashSet<String>();
private final Set<String> unmatchedSet = new HashSet<String>();
private int minLen;
private int maxLen;
public boolean wordBreak(String s, List<String> wordDict) {
if (wordDict.size() == 0) {
if (s.length() == 0) {
return true;
} else {
return false;
}
}
unmatchedSet.clear();
System.out.println("s.length=" + s.length());
int firstLen = wordDict.get(0).length();
maxLen = firstLen;
minLen = firstLen;
// init word set and get max/min lenth of words
for (String word: wordDict) {
wordSet.add(word);
int wordLen = word.length();
if (wordLen > maxLen) {
maxLen = wordLen;
}
if (wordLen < minLen) {
minLen = wordLen;
}
}
return matchWord(s);
}
public boolean matchWord(String s) {
if (unmatchedSet.contains(s)) {
return false;
}
String word;
for (int wordLen = Math.min(maxLen,s.length()); wordLen >= minLen; wordLen--) {
word = s.substring(0, wordLen);
//System.out.println("s="+s+", word="+word+", wordLen="+wordLen);
// match left sentence
if (wordSet.contains(word)) {
if (wordLen == s.length()) {
return true;
}
boolean matched = matchWord(s.substring(wordLen));
if (matched) {
return true;
}
}
}
System.out.println("-- add unmatched = " +s);
unmatchedSet.add(s);
return false;
}
}
解法1: 递归遍历,通过使用unmatched set 来记录不匹配的分支,减少重复匹配情况。
解法2: 记录所有匹配成功和失败的结果。
public class Solution {
private HashMap<String, Boolean> canSeparate;
public boolean wordBreak(String s, List<String> wordDict) {
if (s.isEmpty()) return false;
canSeparate = new HashMap<>();
return canBeSeparated(s, wordDict);
}
private boolean canBeSeparated(String s, List<String> wordDict) {
if (s.isEmpty()) return true;
if (canSeparate.containsKey(s)) return canSeparate.get(s);
for (String word : wordDict) {
if (s.startsWith(word)) {
if (canBeSeparated(s.substring(word.length(), s.length()), wordDict)) {
canSeparate.put(s, true);
return true;
}
}
}
canSeparate.put(s, false);
return false;
}
}
https://leetcode.com/problems/word-break/
https://leetcode.com/problems/word-break/discuss/731220/Java-Solution-beats-80