一、知识点:
动态规划
二、文字分析:
我们定义一个长度为n
的布尔数组dp
,其中dp[i]
表示字符串s
的前i
个字符是否可以由词汇表中的单词拆分而成。
状态转移方程为:
- 如果
dp[j]
为true且字符串s
从第j+1
个字符到第i
个字符(即s.substring(j+1, i+1)
)在词汇表中,也即wordDict.contains(s.substring(j+1, i+1))
为true,则dp[i]
为true。
初始化:
dp[0]
为true,表示空字符串可以由词汇表中的单词拆分而成。
最终结果为dp[n]
,其中n
为字符串s
的长度。
时间复杂度:
- 两层循环遍历字符串
s
的所有子串,时间复杂度为O(n^2)。 - 在内层循环中,判断子串是否在词汇表中需要O(1)的时间(使用Set存储词汇表并进行查找)。
因此,算法的总体时间复杂度为O(n^2)。
空间复杂度:
- 需要一个长度为n+1的布尔数组
dp
来保存每个子串是否可以拆分成词汇表中的单词,空间复杂度为O(n+1)。 - 需要一个Set来存储词汇表中的单词,空间复杂度取决于词汇表的大小,可以认为是O(m),其中m是词汇表中单词的数量。
因此,算法的总体空间复杂度为O(n+m)。
三、编程语言:
java
四、正确代码:
import java.util.*; public class Solution { public boolean wordBreak(String s, String[] wordDict) { int n = s.length(); Set<String> wordSet = new HashSet<>(Arrays.asList(wordDict)); boolean[] dp = new boolean[n + 1]; dp[0] = true; for (int i = 1; i <= n; i++) { for (int j = 0; j < i; j++) { if (dp[j] && wordSet.contains(s.substring(j, i))) { dp[i] = true; break; } } } return dp[n]; } }