25.单词拆分(medium)

1.题目链接:

139. 单词拆分 - 力扣(LeetCode)139. 单词拆分 - 给你一个字符串 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 中的所有字符串 互不相同https://leetcode.cn/problems/word-break/description/

2.题目描述:

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词   拼接出 s 。​
    注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

示例 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​

3. 解法(动态规划):

算法思路:

1. 状态表示:

对于线性 dp ,我们可以用「经验 + 题目要求」来定义状态表示:​

i.

以某个位置为结尾,巴拉巴拉;

ii. 以某个位置为起点,巴拉巴拉。

这里我们选择比较常用的方式,以某个位置为结尾,结合题目要求,定义一个状态表示:

dp[i]  表示:[0, i]  区间内的字符串,能否被字典中的单词拼接而成。​

2. 状态转移方程:

对于 dp[i] ,为了确定当前的字符串能否由字典里面的单词构成,根据最后一个单词的起始位j ,我们可以将其分解为前后两部分:​

i.

前面一部分 [0, j - 1]  区间的字符串;​

ii. 后面一部分 [j, i]  区间的字符串。​

其中前面部分我们可以在 dp[j - 1]  中找到答案,后面部分的子串可以在字典里面找到。​

因此,我们得出一个结论:当我们在从 0 ~ i  枚举 j  的时候,只要 dp[j - 1] = true并且后面部分的子串 s.substr(j, i - j + 1) 能够在字典中找到,那么 dp[i] = true

3. 初始化:

可以在最前面加上一个「辅助结点」,帮助我们初始化。使用这种技巧要注意两个点:

i.     辅助结点里面的值要「保证后续填表是正确的」;

ii. 「下标的映射关系」。

在本题中,最前面加上一个格子,并且让 dp[0] = true ,可以理解为空串能够拼接而成。​

其中为了方便处理下标的映射关系,我们可以将字符串前面加上一个占位符 s = ' ' + s ,这

样就没有下标的映射关系的问题了,同时还能处理「空串」的情况。

4. 填表顺序:

显而易见,填表顺序「从左往右」。

5. 返回值:

由「状态表示」可得:返回 dp[n]  位置的布尔值。​

哈希表优化的小细节:

在状态转移中,我们需要判断后面部分的子串「是否在字典」之中,因此会「频繁的用到查询操

作」。为了节省效率,我们可以提前把「字典中的单词」存入到「哈希表」中。

Java算法代码:

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        // 1.优化1:将字典里面的单词存放在哈希表中
        Set<String> hash = new HashSet(wordDict);

        int n = s.length();
        boolean[] dp = new boolean[n +1];
        dp[0] = true;
        s = " " + s;
        for(int i = 1; i <= n; i++){
            for(int j = i; j >= 1; j--){
                if(dp[j-1] && hash.contains(s.substring(j,i + 1))){
                    dp[i] = true;
                    break;//优化2
                }
            }
        }
        return dp[n];
    }
}

运行结果:

动态规划:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值