leetcode:139. 单词拆分
题目
给你一个字符串 s
和一个字符串列表 wordDict
作为字典。请你判断是否可以利用字典中出现的单词拼接出 s
。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
示例:
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。
输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。
注意,你可以重复使用字典中的单词。
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false
解答 & 代码
动态规划
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
// 将字典中的字符串存入哈希表,并统计字典中字符串的最小长度和最大长度
unordered_set<string> wordMap;
int minLen = INT_MAX; // 字典中字符串的最小长度
int maxLen = 0; // 字典中的字符串的最大长度
for(int i = 0; i < wordDict.size(); ++i)
{
wordMap.insert(wordDict[i]);
minLen = min(minLen, (int)wordDict[i].size());
maxLen = max(maxLen, (int)wordDict[i].size());
}
// 1. 动态规划数组:dp[i] 代表字符串前 i 个字符 s[0,..,i-1] 能否拆成字典中的单词
vector<bool> dp(s.size() + 1, false);
// 2. 初始化:长度为 0 时,设为 true
dp[0] = true;
// 3. 状态转移
// 如果存在 0 <= j < i,dp[0] == true 且 s[j,..,i-1] 在字典中存在,则 dp[i]=true
for(int i = 1; i <= s.size(); ++i)
{
// 剪枝,可以通过字典中字符串的最小长度和最大长度来缩减 j 的范围
int start = max(0, i - maxLen);
int end = i - minLen;
for(int j = start; j <= end; ++j)
{
if(dp[j] == true && wordMap.find(s.substr(j, i - j)) != wordMap.end())
{
dp[i] = true;
break;
}
}
}
return dp[s.size()];
}
};
复杂度分析:设字符串 s
长为 N
- 时间复杂度
:
- 空间复杂度 O(N):哈希表和动态规划数组
执行结果:
执行结果:通过
执行用时:4 ms, 在所有 C++ 提交中击败了 87.55% 的用户
内存消耗:7.6 MB, 在所有 C++ 提交中击败了 77.07% 的用户