题目描述:
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。
示例 1:
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。
示例 2:
输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以被拆分成 "apple pen apple"。
注意你可以重复使用字典中的单词。
示例 3:
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false
分析思考:
1、要写出来递归的做法
2、仔细分析重叠子问题
dp解法关键:两次循环检查从0-i之间每一个substring(0,j)和substring(j,i)是否在字典里面,而前者是重叠的子问题,当且仅当第一个为true且第二个也是true的时候才返回true,因为一个字符串想要满足true,必须拆成的两部分分别都在在字典中才是符合条件的,所以需要检查第一个字符串是重叠计算的子问题,可以通过动态规划减少计算量
有两个注意:dp[0] = 0,还有就是但凡遇到一个true就可以返回这个dp值为true
贴上Java代码:
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
if ( s.length() <= 0 ) {
return true;
}
if ( wordDict.size() <= 0 ) {
return false;
}
int n = s.length();
if ( wordDict.size() == 1 ) {
return s.equals(wordDict.get(0));
}
//return helper(s , new HashSet(wordDict) , 0);
//动态规划解法
boolean dp[] = new boolean[n+1];
dp[0] = true;
for( int i = 1 ; i <= n ; i++ ) {
dp[i] = false;
}
for ( int i = 1 ; i <= n ; i++ ) {
for( int j = 0 ; j <= i ; j++ ) {
//j等于i也可以,下面判断不执行就是了
if ( dp[j] && wordDict.contains( s.substring(j,i)) ) {
dp[i] = true;
break;
}
}
}
return dp[n];
}
//递归(超时)
// public Boolean helper( String s , Set<String> wordDict , int start ) {
// if ( start == s.length() ) {
// return true;
// }
// for ( int end = start+1 ; end <= s.length() ; end++ ) {
// if ( wordDict.contains(s.substring(start,end))
// && helper(s,wordDict,end) ) {
// return true;
// }
// }
// return false;
// }
}