每日挑战(C++版)
在这里,我将开始每天练习LeetCode算法题,并将个人解决方案放在这里。
需求介绍
给你一个字符串 s
和一个字符串列表 wordDict
作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s
则返回 true
。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
限制:
1 <= s.length <= 300
1 <= wordDict.length <= 1000
1 <= wordDict[i].length <= 20
s
和wordDict[i]
仅由小写英文字母组成wordDict
中的所有字符串 互不相同
测试实例:
- 实例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
个人分析
这个题目比较简短,概括来说就是判断数组wordDict中的元素能否组合成字符串s。从这个需求可以分析出,我们是需要构建一个新字符串,然后判断这个构建出来的新字符串与字符串s是否完全一致。
不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。这说明了在对新字符串进行构建的时候,需要从对整个数组从头到尾进行遍历。
有了上述题目背后我得到的信息,我第一反应想到的就是使用深度优先遍历DFS进行新字符串的构建。在每一次递归的时候判断构建的字符串是否与字符串s的前缀字符串相同,如果相同继续递归,不相同的话就使用下一个数组中的元素,在遍历完整个数组都拼接不出相同的前缀子字符串,那就回溯。因此判断新字符串的长度与字符串s长度相同时就说明结果为true,可以由字典单词拼接出来。在这种思想下,我写下了第一段代码。
第一段代码在提交的时候超时了!!。我发现这种朴素的拼接,当字典足够大的时候,整个代码完全不work。因为会重复出现很多已经出现过的新字符串,在这种情况下相当于是重新浪费了一遍时间,效率非常低。因此,我对这个dfs进行了改进,将这些拼接过的字符串用哈希表保存起来。如果当前拼接的字符串在哈希表中,那么直接跳过即可。于是就写出了第二段代码。
代码实现
朴素DFS
class Solution {
public:
bool dfs(string& s, vector<string>& wordDict, int idx_s, int idx_wd)
{
if(idx_s == s.length())
{
return true;
}
if(idx_wd == wordDict.size())
{
return false;
}
for(int i = idx_wd; i < wordDict.size(); i++)
{
int wordLength = wordDict[i].size();
string subStr = s.substr(idx_s, wordLength);
bool flag;
if(subStr == wordDict[i])
{
flag = dfs(s, wordDict, idx_s + wordLength, 0);
}
else
{
flag = dfs(s, wordDict, idx_s, i + 1);
}
if(flag)
{
return true;
}
}
return false;
}
bool wordBreak(string s, vector<string>& wordDict) {
return dfs(s, wordDict, 0 , 0);
}
};
DFS+哈希表
class Solution {
public:
bool dfs(string& s, vector<string>& wordDict, unordered_set<string>& tree, string path)
{
bool flag = false;
if(path == s)
{
return true;
}
if(tree.find(path) != tree.end())
{
return false;
}
tree.insert(path);
for(string word:wordDict)
{
string subStr = path + word;
bool flag = false;
if(s.substr(0, subStr.length()) == subStr)
{
flag = dfs(s, wordDict, tree, subStr);
}
if(flag)
return true;
}
return false;
}
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> tree;
return dfs(s, wordDict, tree, "");
}
};
总结
上诉代码在时间上超过了55.89%的用户,内存上超过了15.15%的用户。