LeetCode-139. 单词的拆分(中等)
题目地址:https://leetcode-cn.com/problems/word-break/
文章目录
1. 题目描述及示例
给你一个字符串 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
2. 题解和代码实现
在这里采用动态规划的方法进行实现。对于字符串s,我们可以使用一个dp[s.size()+1] 来进行存储对应于该位置在字符串的每个位置之前的所形成的子串能否有单词表进行实现。由对于字符串中 s 的 i 位置,改位置的dp[i],取决于,在 i 之前的某一 j 之前的子串以及 j ~ i 之间的子串均能用单词表进行表示出来,这样进行一步一步的更新dp[i] 即可。
2.1 初始化
在这里初始化 dp[0] = 1,而且dp中所对应的dp[0],代表的是 s 中的空串 “” ,显然空串能够用单词表进行表示出来,而dp[1],则为 s 中的第一个字符。
为什么这样设置dp,为什么初始化 dp[0] = 1?
在这里当我们进行遍历时,每一个字符串它的子串包含着空串和它自身,所以利用该操作,可以很好的把这两个都给包含起来。
2.2 状态转移方程
对于前面的解释中,我们已经知道,对dp[i] 的值,由dp[j] 和j~i 之间的子串是否能够由单词表进行表示来共同决定。即当dp[j]==1&&findWord(s.substr(j,i-j), wordDict)==1成立时,才有 dp[i] = 1。
在这里的findWord() 方法是用于查找字符串是否在单词表中。
bool findWord(string str,vector<string>& wordDict){
for(string s: wordDict){
if(str==s){
return true;
}
}
return false;
}
代码实现(C++ 2022-4-3)
class Solution {
bool findWord(string str,vector<string>& wordDict){
for(string s: wordDict){
if(str==s){
return true;
}
}
return false;
}
public:
bool wordBreak(string s, vector<string>& wordDict) {
vector<bool> dp(s.size()+1); // 注意好好得进行初始化,0就是要初始化为0
dp[0] = 1; // 进行初始化 第一个元素,当为空的时候,肯定也能够用字典进行表示
for(int i=1;i<=s.size();i++){
for(int j=0;j<i;j++){ //对于i位置的能否进行表示,要看i之前的都能够进行表示
// 定位是 dp[j] ,j之前的能够进行表示,和j之后的在单词表中
// 判断j之后的是否在单词表中
if(dp[j]&&findWord(s.substr(j,i-j), wordDict)){ // 使用dp[0] 已经进行包含了,所有i之前所有字符得意思
dp[i] = 1;
break;
}
}
}
return dp[s.size()];
}
};
3. 总结
这里的实现较为简单,实现的方法有所单一,应尝试利用其他方法进行实现。