文章目录
day46学习内容
day46主要内容
- 单词拆分
- 多重背包理论基础
声明
本文思路和文字,引用自《代码随想录》
一、单词拆分
1.1、动态规划五部曲
1.1.1、 确定dp数组(dp table)以及下标的含义
表示字符串 s 的前 i 个字符(具体而言,是从字符串的开始到位置 i-1,因为字符串索引是从0开始的)能否被分割成一个或多个在字典 wordDict 中出现的单词。
换句话说,如果 dp[i] 为 true,则意味着存在至少一种方式将 s 的前 i 个字符分割成若干个单词,这些单词全部包含在给定的单词列表 wordDict 中。这里的 i 取值范围是从 0 到 s.length(),其中 dp[0] 特别表示空字符串,按照定义,空字符串可以被视为可以被分割(即没有需要分割的内容),因此 dp[0] 初始化为 true。
1.1.2、确定递推公式
想不到,抄的题解。。
1.1.3、 dp数组如何初始化
dp[0] = true;
1.1.4、确定遍历顺序
先遍历物品后遍历背包。
1.2、代码
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
HashSet<String> set = new HashSet<>(wordDict);
boolean[] dp = new boolean[s.length() + 1];
dp[0] = true;
for (int i = 1; i <= s.length(); i++) {
for (int j = 0; j < i && !dp[i]; j++) {
if (set.contains(s.substring(j, i)) && dp[j]) {
dp[i] = true;
}
}
}
return dp[s.length()];
}
}
1.2.1、如何理解这段代码
初始化
- 定义一个布尔型数组
dp
,其长度为s.length() + 1
。dp[i]
表示字符串s
的前i
个字符(即s.substring(0, i)
)能否被拆分为一个或多个在字典中出现的单词。 dp[0] = true
表示空字符串默认是可以被拆分的,这是动态规划的基础情况。
动态规划过程
- 外层循环:遍历字符串
s
的每一个字符,索引为i
,从 1 开始到s.length()
(包括)。i
代表当前考虑的字符串长度。 - 内层循环:对于每个
i
,再次从头遍历到i
,索引为j
,用于尝试找到所有可能的拆分点。j
表示尝试将字符串拆分为两部分:s[0...j]
和s[j+1...i]
。- 检查条件:
dp[j]
是否为true
,即s[0...j]
部分是否可以被成功拆分。s.substring(j, i)
是否存在于set
中,即s[j+1...i]
部分是否为字典中的一个单词。
- 如果这两个条件同时满足,说明找到了一种方式将
s[0...i]
成功拆分,将dp[i]
设置为true
。
- 检查条件:
返回结果
- 最后返回
dp[s.length()]
的值。如果为true
,则表示整个字符串s
可以被拆分为一个或多个在字典中出现的单词;否则,不可以。
举个例子
假设 s = "leetcode"
,wordDict = ["leet", "code"]
:
- 初始化
dp = [true, false, false, false, false, false, false, false, false]
。 - 当
i = 4
且j = 0
时,dp[0]
为true
且s.substring(0, 4)
(即 “leet”)在set
中,因此dp[4]
被设置为true
。 - 同理,当
i = 8
且j = 4
时,dp[4]
为true
且s.substring(4, 8)
(即 “code”)在set
中,因此dp[8]
也被设置为true
。 - 最终
dp[8]
为true
,表示整个字符串可以被拆分。
二、完全背包理论基础
一刷先放过自己。
总结
1.感想
- 单词拆分这一题,状态转移方程想不出来一点。。根本想不到
2.思维导图
本文思路引用自代码随想录,感谢代码随想录作者。