139. 单词拆分
标题给定一个非空字符串 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
采用动态规划方法
- 如果[0,j]可以被分词字典里的单词,检查[j + 1, i]也是字典里的单词,那么[0,i]也可以被分成字典里的单词
- 定义dp[i],dp[i]的含义是,前i个字符组成的子串能否被分割,令dp[0] = true
- 得出dp[i] = dp[k] && check(k + 1, i),check函数是判断该子串是否在字典内
对于检查一个字符串是否出现在给定的字符串列表里一般可以考虑哈希表来快速判断
public class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
Set<String> wordDictSet = new HashSet(wordDict);
//定义一个HashSet,它不会出现重复的元素,无序的,可以含有空元素。
boolean[] dp = new boolean[s.length() + 1];
dp[0] = true;
//表示空串且合法,边界条件
for (int i = 1; i <= s.length(); i++) {
for (int j = 0; j < i; j++) {
//判断子串s[j,i]是否存在在字典集合中
if (dp[j] && wordDictSet.contains(s.substring(j, i))) {
dp[i] = true;
break;
}
}
}
return dp[s.length()];
}
}
复杂度分析
- 时间复杂度:O(n^2),其中 n 为字符串 s 的长度。我们一共有 O(n) 个状态需要计算,每次计算需要枚举 O(n) 个分割点,哈希表判断一个字符串是否出现在给定的字符串列表需要 O(1)的时间,因此总时间复杂度为 O(n^2)
- 空间复杂度:O(n) ,其中n 为字符串 s 的长度。我们需要 O(n) 的空间存放dp值以及哈希表亦需要O(n) 的空间复杂度,因此总空间复杂度为 O(n)