Skip to main content

139.单词拆分

标签: dynamic-programming, hash-table

难度: Medium

通过率: 47.58%

原题链接: https://leetcode.com/problems/word-break/description/

题目描述

给定一个字符串 ss 和一个字符串列表 wordDictwordDict 作为字典,如果 ss 可以拆分成一个由字典中单词组成的空格分隔序列,返回 truetrue。注意:字典中的单词可以重复使用。

解题思路

这个问题可以用动态规划来解决。我们用 dp[i]dp[i] 表示字符串 s[0:i]s[0:i] 是否可以拆分成字典中的单词序列。为了实现动态规划,需要以下步骤:

  1. 初始化:定义一个大小为 n+1n+1 的布尔型数组 dpdp,其中 nn 是字符串 ss 的长度。将 dp[0]dp[0] 设为 truetrue,因为空字符串总是可以被认为是由空单词组成的。
  2. 遍历字符串 ss 的每个位置 ii,对于每个位置 ii,在字典中检查每个单词 wordword
    • 如果 wordword 可以用在 ii 位置上的话(即 s[ilen(word):i]==words[i-len(word):i]==word),并且 dp[ilen(word)]dp[i-len(word)]truetrue,那么 dp[i]dp[i] 就为 truetrue
  3. 最后的答案为 dp[n]dp[n],它表示整个字符串是否可以被拆分。

代码实现

def wordBreak(s, wordDict):
# 创建一个集合来快速查找字典中的单词
word_set = set(wordDict)
# dp[i] 表示 s 的前 i 个字符是否可以由字典中的单词组成
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 word_set:
dp[i] = True
break
# 返回整体字符串是否能被切割、组成
return dp[len(s)]

复杂度分析

时间复杂度:O(n2m)O(n^2 \cdot m),其中 nn 是字符串 ss 的长度,mm 是字典中最长单词的长度。内循环最多需要扫描 nn 个位置,且每个子字符串需要在集合中检查。
空间复杂度:O(n)O(n),需要一个大小为 n+1n+1 的数组 dpdp