前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >单词拆分\\

单词拆分\\

作者头像
狼啸风云
发布2023-12-23 09:21:06
1010
发布2023-12-23 09:21:06
举报

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。

注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

示例 1:

代码语言:javascript
复制
输入: 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

思路和算法

我们定义

\textit{dp}[i]
\textit{dp}[i]

表示字符串 sss 前 iii 个字符组成的字符串

s[0..i-1]
s[0..i-1]

是否能被空格拆分成若干个字典中出现的单词。从前往后计算考虑转移方程,每次转移的时候我们需要枚举包含位置

i-1
i-1

的最后一个单词,看它是否出现在字典中以及除去这部分的字符串是否合法即可。公式化来说,我们需要枚举

s[0..i-1]
s[0..i-1]

中的分割点

j
j

,看

s[0..j-1]
s[0..j-1]

组成的字符串

s_1
s_1

(默认

j = 0
j = 0

s_1
s_1

为空串)和

s[j..i-1]
s[j..i-1]

组成的字符串

s_2
s_2

是否都合法,如果两个字符串均合法,那么按照定义

s_1
s_1

s_2
s_2

拼接成的字符串也同样合法。由于计算到

\textit{dp}[i]
\textit{dp}[i]

时我们已经计算出了

\textit{dp}[0..i-1]
\textit{dp}[0..i-1]

的值,因此字符串

s_1
s_1

是否合法可以直接由 dp[j]dp[j]dp[j] 得知,剩下的我们只需要看

s_2
s_2

是否合法即可,因此我们可以得出如下转移方程:

\textit{dp}[i]=\textit{dp}[j]\ \&\&\ \textit{check}(s[j..i-1])
\textit{dp}[i]=\textit{dp}[j]\ \&\&\ \textit{check}(s[j..i-1])

其中

\textit{check}(s[j..i-1])
\textit{check}(s[j..i-1])

表示子串

s[j..i-1]
s[j..i-1]

是否出现在字典中。

对于检查一个字符串是否出现在给定的字符串列表里一般可以考虑哈希表来快速判断,同时也可以做一些简单的剪枝,枚举分割点的时候倒着枚举,如果分割点

j
j

i
i

的长度已经大于字典列表里最长的单词的长度,那么就结束枚举,但是需要注意的是下面的代码给出的是不带剪枝的写法。

对于边界条件,我们定义

\textit{dp}[0]=true
\textit{dp}[0]=true

表示空串且合法。

有能力的读者也可以考虑怎么结合字典树

\text{Trie}
\text{Trie}

来实现,这里不再展开。

代码语言:javascript
复制
class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        auto wordDictSet = unordered_set <string> ();
        for (auto word: wordDict) {
            wordDictSet.insert(word);
        }

        auto dp = vector <bool> (s.size() + 1);
        dp[0] = true;
        for (int i = 1; i <= s.size(); ++i) {
            for (int j = 0; j < i; ++j) {
                if (dp[j] && wordDictSet.find(s.substr(j, i - j)) != wordDictSet.end()) {
                    dp[i] = true;
                    break;
                }
            }
        }

        return dp[s.size()];
    }
};

复杂度分析

时间复杂度:

O(n^2)
O(n^2)

,其中

n
n

为字符串

s
s

的长度。我们一共有

O(n)
O(n)

个状态需要计算,每次计算需要枚举

O(n)
O(n)

个分割点,哈希表判断一个字符串是否出现在给定的字符串列表需要

O(1)
O(1)

的时间,因此总时间复杂度为

O(n^2)
O(n^2)

空间复杂度:

O(n)
O(n)

,其中

n
n

为字符串

s
s

的长度。我们需要

O(n)
O(n)

的空间存放

\textit{dp}
\textit{dp}

值以及哈希表亦需要

O(n)
O(n)

的空间复杂度,因此总空间复杂度为

O(n)
O(n)

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-12-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档