11.1每日一题
140. 单词拆分 II
这道题是139题的拓展,所以先来解决139,139是判断字符串是否可以拆分成字典中的单词,可以想到使用动态规划的方法来解决这道题,设dp[i]是长度为i的字符串能否拆分成单词,那么将字符串i拆解成(0,j)和(j,i)如果这两个字符串都是在字典中出现的单词,那么组合后的i也是字典中的单词,因此转移方程为:dp[i] = dp[j] && wordDict.contains(s.substring(j, i)),当i = 0,即字符串长度为0,规定为合法,理清楚之后就可以写代码了。
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
//首先创建一个hash表方便快速判断字符串是否在字典内
int len = s.length();
Set<String> wordDictSet = new HashSet<>(wordDict);
boolean[] dp = new boolean[len + 1];
//初始化边界值
dp[0] = true;
for(int i = 1; i <= len; i++){
//如果单词长度比较短,从后遍历比较快
for(int j = i - 1; j >= 0; j--){
if(dp[j] && wordDictSet.contains(s.substring(j, i))){
dp[i] = true;
//找到一个证明正确就可以返回了
break;
}
}
}
return dp[len];
}
}
做完了139前置题之后,可以来解决今天的每日一题了,看到题目中提到的所有解,可以想到回朔来解题,再结合139的动态规划就基本可以做出来了。
class Solution {
public List<String> wordBreak(String s, List<String> wordDict) {
//首先创建一个hash表方便快速判断字符串是否在字典内
int len = s.length();
Set<String> wordDictSet = new HashSet<>(wordDict);
boolean[] dp = new boolean[len + 1];
//初始化边界值
dp[0] = true;
for(int i = 1; i <= len; i++){
//如果单词长度比较短,从后遍历比较快
for(int j = i - 1; j >= 0; j--){
if(dp[j] && wordDictSet.contains(s.substring(j, i))){
dp[i] = true;
//找到一个证明正确就可以返回了
break;
}
}
}
//回朔找出所有解
List<String> res = new ArrayList<>();
if(dp[len]){
Deque<String> path = new ArrayDeque<>();
dfs(s, len, wordDictSet, dp, path, res);
return res;
}
return res;
}
void dfs(String s, int len, Set<String> wordDictSet, boolean[] dp, Deque<String> path, List<String> res){
//终止条件
if(len == 0){
res.add(String.join(" ", path));
return;
}
for(int i = len - 1; i >= 0; i--){
String suffix = s.substring(i, len);
if(wordDictSet.contains(suffix) && dp[i]){
path.addFirst(suffix);
dfs(s, i, wordDictSet, dp, path, res);
path.removeFirst();
}
}
}
}