9.16单词拆分(LC139-M)

算法:

这道题可以用回溯,但是可能会超时

可以用背包问题解决:

物品:单词

背包:字符串:

单词能否组成字符串s,就是问物品能不能把背包装满。

拆分时可以重复使用字典中的单词,就是完全背包!

动规五部曲:

1.确定dp数组及其下标:

dp[i]:i为字符串的长度(装满背包的容量);

dp[i]是一个布尔值:dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词

2.确定递推公式:

如果确定dp[j] 是true,且 [j, i] 这个区间的子串出现在字典里,那么dp[i]一定是true。(j < i )。

所以递推公式是

if([j, i] 这个区间的子串出现在字典里 && dp[j]是true) 那么 dp[i] = true。

3.dp初始化

dp数组为布尔量,所以初始化只能赋值true或false

dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都是false了

但题目中说了“给定一个非空字符串 s” 所以测试数据中不会出现i为0的情况,那么dp[0]初始为true完全就是为了推导公式。

下标非0的dp[i]初始化为false,只要没有被覆盖说明都是不可拆分为一个或多个在字典中出现的单词。

4.确定遍历顺序

完全背包,要讨论两层for循环的前后顺序。

如果求组合数就是外层for循环遍历物品,内层for遍历背包

如果求排列数就是外层for遍历背包,内层for循环遍历物品

本题其实我们求的是排列数。 拿 s = "applepenapple", wordDict = ["apple", "pen"] 举例。

"apple", "pen" 是物品,那么我们要求 物品的组合一定是 "apple" + "pen" + "apple" 才能组成 "applepenapple"。

"apple" + "apple" + "pen" 或者 "pen" + "apple" + "apple" 是不可以的,那么我们就是强调物品之间顺序。

所以说,本题一定是 先遍历 背包,再遍历物品。

5.举例推导dp

1表示true,0表示false。最终返回dp[s.size()]

正确代码:

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        HashSet<String> wordset = 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]==false;j++){
                if(wordset.contains(s.substring(j,i)) && dp[j]){
                    dp[i]=true;
                }
            }
        }
        return dp[s.length()];

    }
}

注意:

1.将列表转为哈希表HashSet,提升查找的时间效率

当直接使用列表进行单词的查找时,通常需要遍历整个列表来查找目标单词。这意味着在最坏情况下,需要检查列表中的每个单词,直到找到目标单词或者确定其不存在。因此,时间复杂度是O(n),其中n是列表中单词的数量。

在列表中进行查找时,需要逐个比较每个单词,直到找到匹配的单词或者遍历完整个列表。如果列表中的单词数量很大,那么查找操作可能会花费较长的时间。

相比之下,使用哈希表(或者哈希集)进行查找可以在平均情况下实现O(1)的时间复杂度,因为哈希表允许直接计算目标单词的存储位置,从而实现快速的查找操作。

2.两个for循环:

第一个: for(int i=1;i<=s.length();i++)

i从1开始,因为i要比j大

i的索引最大到s.length(),因为dp的长度为s.length()+1,dp的长度算上了初始化的dp[0]

第二个:for(int j=0;j<i && dp[i]==false;j++)

初始化的时候dp[i]=false(除了dp[0]),所以要先判断dp[i]是否被赋值过(即是否还是false),只有没被赋值过,才有必要更新。

时间空间复杂度:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值