题目:
Given a string s and a dictionary of words dict, determine if s can be break into a space-separated sequence of one or more dictionary words.
Example
Given s = "lintcode"
, dict = ["lint", "code"]
.
Return true because "lintcode" can be break as "lint code"
.
思路:
用一个布尔数组canSeg[i]表示给定的string的前[i]个子串(即s.substring(0, i))是否可以被划分。
这里注意的是substring(beginIndex, endIndex)中,不包含endIndex的字符,所以canSeg的长度应该是string的长度+1。 第一次就wa在了这个上面。
所以状态方程是这样 canSeg[i] = true if (canSeg[j] == true && s.substring(j, i) in dict)。初始值设为 canSeg[0] = true
小优化:
本来两层for循环可以写为 for( int i = 1; i <= length; i++ ) for (j = 0; j < i; j++) 但是考虑到word的长度一般比较小,在string很长的时候,前面很多很多此的j循环其实是无效的,比如string = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaba"; dict = ["a", "b"], 在i循环到最后时,大部分的j循环并不会改变canSeg[i]的值,因为substring太长了,远远超过maxWordLength,肯定不在在字典里。所以考虑只让j在每次最多循环maxWordLength次,即可以从后向前找。
本来答案没怎么看明白,小优化是自己睡觉的时候突然想到的。
public class Solution { /** * @param s: A string s * @param dict: A dictionary of words dict */ //思路:F(x) = true if F(i) == true && string(i,x) in dict public int maxLengthWord(Set<String> dict) { int maxLength = 0; for (String word : dict) { maxLength = Math.max(maxLength, word.length()); } return maxLength; } public boolean wordBreak(String s, Set<String> dict) { // write your code here if (s == null || s.length() == 0) { return true; } int wordlen = maxLengthWord(dict); // canSeg[i] 代表i之前的部分能不能被分,不包括i boolean[] canSeg = new boolean[s.length() + 1]; canSeg[0] = true; String word; for (int i = 1; i <= s.length(); i++) { for(int j = i; j >= 0 && i - j <= wordlen; j--) { word = s.substring(j, i); if (canSeg[j] && dict.contains(word)) { canSeg[i] = true; break; } } } return canSeg[s.length()]; } }