题目描述
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。
说明:
- 分隔时可以重复使用字典中的单词。
- 你可以假设字典中没有重复的单词。
样例
输入:
s = "catsanddog"
wordDict = ["cat", "cats", "and", "sand", "dog"]
输出:
[
"cats and dog",
"cat sand dog"
]
输入:
s = "pineapplepenapple"
wordDict = ["apple", "pen", "applepen", "pine", "pineapple"]
输出:
[
"pine apple pen apple",
"pineapple pen apple",
"pine applepen apple"
]
解释: 注意你可以重复使用字典中的单词。
输入:
s = "catsandog"
wordDict = ["cats", "dog", "sand", "and", "cat"]
输出:
[]
算法分析
LeetCode139
单词拆分的思路
- 1、将
wordDict
链表中所有的元素放进set
中,便于查询 - 2、如图所示
此题的搜索
- 3、若
f[n]
为true
,则进行dfs
,把所有的情况都找出来 - 4、
dfs(u,path)
表示,从u
位置开始往后枚举下一个单词t = s[u,i]
,若f[i]
为true
,且set
中包含此单词,则表示t
单词可以填写到path
中,继续从i + 1
位置递归到下一层
时间复杂度
- 动态规划的时间复杂度是 $O(n^3)$
- 递归枚举的时间复杂度与方案数相等,为指数级。
Java 代码
class Solution {
static List<String> ans = new ArrayList<String>();
static HashSet<String> set = new HashSet<String>();
static int n;
static boolean[] f;
static void dfs(String s, int u, String path)
{
if(u == n + 1)
{
ans.add(path);
return ;
}
for(int i = u;i <= n;i ++)
{
String t = s.substring(u, i + 1);
if(f[i] && set.contains(t))
{
String next = path.length() == 0 ? t : path + " " + t ;
dfs(s, i + 1, next);
}
}
}
public List<String> wordBreak(String s, List<String> wordDict) {
ans.clear();
set.clear();
for(String t : wordDict) set.add(t);
n = s.length();
s = " " + s;
f = new boolean[n + 10];
f[0] = true;
for(int i = 1;i <= n;i ++)
{
for(int j = 1;j <= i;j ++)
{
String t = s.substring(j,i + 1);
if(set.contains(t)) f[i] |= f[j - 1];
}
}
if(!f[n]) return ans;
dfs(s, 1, "");
return ans;
}
}
dfs里为什么用path接收会报错,用next就不会