//给定一个非空字符串 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
//
- 回溯算法
回溯的一般模板
void backtracking(参数) {
if (终⽌条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩⼦的数量就是集合的⼤⼩) ) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
}
由于本题中不要求存储具体的路径,因此没有路径的撤销操作。
撤销的目的是下一次遍历不受影响,此处只有substring操作,一次操作完后,下次的开头是一样的。即第一层遍历取[0.1],[0,2],[0,3] ,所以没有撤销操作。
如果这个时候有添加路径的要求,那么第一层如果结果为【1,2】,下一次符合要求的为【3】,就要把之前的2去掉。
public boolean wordBreak(String s, List<String> wordDict) {
if (wordDict == null || wordDict.isEmpty()) {
return false;
}
Set<String> set = new HashSet<>(wordDict);
return backTrace(s, 0, set);
}
private boolean backTrace(String s, int start, Set<String> set) {
if (s.length() == start) {
return true;
}
for (int i = start; i < s.length(); i++) {
String substring = s.substring(start, i + 1);
if (set.contains(substring)) {
if (backTrace(s, i + 1, set)) {
return true;
}
}
}
return false;
}
改为动态规划
backTrace(s, 0, set)可以看做dp[0]
if (s.length() == start) {
return true;
}
可以看做是dp[n]
由dp[n]–>dp[0]
public boolean wordBreak1(String s, List<String> wordDict) {
if (wordDict == null || wordDict.isEmpty()) {
return false;
}
Set<String> set = new HashSet<>(wordDict);
int n = s.length();
boolean[] dp = new boolean[n + 1];
dp[n] = true;
for (int start = n - 1; start >= 0; start--) {
for (int i = start; i < s.length(); i++) {
String substring = s.substring(start, i + 1);
if (set.contains(substring)) {
if (dp[i + 1]) {
dp[start] = true;
}
}
}
}
return dp[0];
// return dfs(s, 0, set);
}
其实动态 规划与记忆化很类似,不过一个用数组来表示, 一个用Hashmap来表示
public boolean wordBreak(String s, List<String> wordDict) {
if (wordDict == null || wordDict.isEmpty()) {
return false;
}
Set<String> set = new HashSet<>(wordDict);
return backTrace(s, 0, set, new HashMap<>());
}
private boolean backTrace(String s, int start, Set<String> set, Map<Integer, Boolean> map) {
if (s.length() == start) {
return true;
}
if (map.containsKey(start)) {
return map.get(start);
}
for (int i = start; i < s.length(); i++) {
String substring = s.substring(start, i + 1);
if (set.contains(substring)) {
if (backTrace(s, i + 1, set, map)) {
map.put(start, true);
return true;
}
}
}
map.put(start, false);
return false;
}