动态规划:单词差分

目录

题目

 思路

解题过程

初始化

 预处理

动态规划状态转移

最终结果

复杂度

时间复杂度: O(n^2)

空间复杂度: O(n)

code


题目

        给一个字符串 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 中的所有字符串 互不相同

 思路

        在这个问题中,选择使用动态规划(Dynamic Programming, DP)的方法来解决。动态规划是解决此类“分割”或“子问题重叠”问题的强大工具,特别是在需要判断一个字符串是否可以通过某种方式(这里是空格拆分成字典中的单词)完全构建起来时。


解题过程

  • 初始化

  1. 定义一个布尔数组 dp,其中 dp[i] 表示字符串 s 的前 i 个字符(即 s[0:i])是否可以被空格拆分成若干个字典中出现的单词。
  2. 初始化 dp[0] = True,因为空字符串可以被视为已经拆分完成(尽管实际上没有拆分)。
  •  预处理

        将字典 wordDict 转换为一个哈希集合(HashSet),以便在 O(1) 时间复杂度内检查一个单词是否存在于字典中。

  • 动态规划状态转移

  1. 遍历字符串 s 的每个位置 i(从 1 到 len(s))。
  2. 对于每个位置 i,遍历从 0 到 i-1 的每个位置 j 作为分割点。
  3. 检查 s[j:i](即从位置 j 到 i-1 的子串)是否在哈希集合中。
  4. 如果 s[j:i] 在哈希集合中且 dp[j] 为 True,则设置 dp[i] = True
  5. 如果在任何时候找到 dp[i] = True,则无需继续检查更小的 j 值(这是一个可选的优化,但通常不会显著改变总体时间复杂度)。
  • 最终结果

   dp[len(s)] 的值将告诉我们整个字符串 s 是否可以被空格拆分成字典中的单词。


复杂度

  • 时间复杂度: O(n^2)

        其中 n 是字符串 s 的长度。我们需要遍历字符串 s 的每个位置 i(O(n)),并且在每个位置 i 上,我们需要遍历从 0 到 i-1 的每个位置 j(O(n)),总共 O(n^2) 次操作。哈希表查找是 O(1) 的,因此不增加总体时间复杂度的阶数。

  • 空间复杂度: O(n)

        其中 n 是字符串 s 的长度。我们需要一个长度为 n+1 的布尔数组 dp 来存储状态,以及一个哈希集合来存储字典中的单词。哈希集合的空间复杂度通常取决于字典中单词的数量和长度,但在这里我们可以将其视为与 n 成正比(在最坏情况下,字典包含所有可能的长度为 1 到 n 的子串),但通常情况下会远小于这个界限。因此,总体空间复杂度可以认为是 O(n)。


code

class Solution(object):
    def wordBreak(self, s, wordDict):
        wordSet = set(wordDict)  # 将字典转换为集合以加速查找
        dp = [False] * (len(s) + 1)
        dp[0] = True  # 空字符串可以被拼接

        for i in range(1, len(s) + 1):
            for j in range(i):
                if dp[j] and s[j:i] in wordSet:
                    dp[i] = True
                    break

        return dp[len(s)]

  • 16
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值