题目:
给你一个字符串 s
和一个字符串列表 wordDict
作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s
则返回 true
。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
示例 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 <= s.length <= 300
1 <= wordDict.length <= 1000
1 <= wordDict[i].length <= 20
s
和wordDict[i]
仅由小写英文字母组成wordDict
中的所有字符串 互不相同
解法:动态规划
问题分析
我们需要判断字符串 s
是否可以由字典 wordDict
中的单词拼接而成。字典中的单词可以重复使用,且不需要全部使用。
解题思路
这是一个典型的动态规划问题。我们可以使用动态规划来解决:
-
定义状态:
-
设
dp[i]
表示字符串s
的前i
个字符(即s[0..i-1]
)是否可以被字典中的单词拼接而成。
-
-
状态转移方程:
-
对于每个位置
i
,我们需要检查是否存在一个j
(0 <= j < i
),使得:-
dp[j]
为true
(即s[0..j-1]
可以被拼接而成)。 -
子串
s[j..i-1]
在字典wordDict
中存在。
-
-
如果存在这样的
j
,则dp[i] = true
。
-
-
初始条件:
-
dp[0] = true
,表示空字符串可以被拼接而成。
-
-
最终结果:
-
dp[s.length()]
即为所求。
-
代码实现
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
// 将字典转换为哈希集合,方便快速查找
unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
// 动态规划数组
int n = s.length();
vector<bool> dp(n + 1, false);
dp[0] = true; // 空字符串可以被拼接
// 填充 dp 数组
for (int i = 1; i <= n; i++) {
for (int j = 0; j < i; j++) {
// 如果 dp[j] 为 true,且子串 s[j..i-1] 在字典中
if (dp[j] && wordSet.find(s.substr(j, i - j)) != wordSet.end()) {
dp[i] = true;
break; // 找到一个满足条件的 j 即可
}
}
}
// 返回结果
return dp[n];
}
};
代码解释
-
哈希集合:
-
将
wordDict
转换为unordered_set<string>
,方便快速查找子串是否在字典中。
-
-
动态规划数组:
-
dp[i]
表示s
的前i
个字符是否可以被拼接而成。 -
初始化
dp[0] = true
,因为空字符串可以被拼接。
-
-
状态转移:
-
对于每个位置
i
,遍历所有可能的j
(0 <= j < i
),检查:-
dp[j]
是否为true
。 -
子串
s[j..i-1]
是否在字典中。
-
-
如果满足条件,则
dp[i] = true
。
-
-
结果:
-
最终返回
dp[n]
,即整个字符串s
是否可以被拼接而成。
-
示例运行
示例 1:
-
输入:
s = "leetcode"
,wordDict = ["leet", "code"]
-
运行过程:
-
dp[0] = true
-
dp[4] = true
(因为s[0..3] = "leet"
在字典中) -
dp[8] = true
(因为s[4..7] = "code"
在字典中)
-
-
输出:
true
示例 2:
-
输入:
s = "applepenapple"
,wordDict = ["apple", "pen"]
-
运行过程:
-
dp[0] = true
-
dp[5] = true
(因为s[0..4] = "apple"
在字典中) -
dp[8] = true
(因为s[5..7] = "pen"
在字典中) -
dp[13] = true
(因为s[8..12] = "apple"
在字典中)
-
-
输出:
true
示例 3:
-
输入:
s = "catsandog"
,wordDict = ["cats", "dog", "sand", "and", "cat"]
-
运行过程:
-
dp[0] = true
-
dp[4] = true
(因为s[0..3] = "cats"
在字典中) -
dp[7] = true
(因为s[4..6] = "and"
在字典中) -
无法找到
dp[9] = true
的条件。
-
-
输出:
false
复杂度分析
-
时间复杂度:
-
外层循环遍历
s
的每个位置,内层循环遍历所有可能的j
,因此时间复杂度为O(n^2)
,其中n
是s
的长度。
-
-
空间复杂度:
-
使用了一个大小为
n + 1
的dp
数组,因此空间复杂度为O(n)
。
-