Leetcode 139. 单词拆分

100 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情

1.题目

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。

注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

示例 1:

输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet""code" 拼接成。

2.思路

本题需要我们判断是否能够使用字典中的单词拼接出字符串,我们需要考虑字符串s中有多个字符,可以组成不同的单词,但是如果前一个字母不能组成单词在词典中找到,那就说明这个字符串是不能由字典的单词组成而一个字符串由多个单词组成,那么我们可以考虑找到一个单词然后再截取剩下的字符串来找到另一个单词。

所以我们可以从第一个字母开始遍历组成子单词,同时在字典中查找是否已经存在该单词,如果已经存在该单词的话那就可以考虑截取剩下的字符串继续这种判断,通过递归的方法来判断是不是能够匹配到。这种思路可以解决我们的问题,但也带来了一个新问题,在某些情况下这个方法的耗时会非常大。

我们既然想到了一个字符串是由多个单词组成,那我们是不是可以把这个字符串拆分成多个字符串呢,如果子字符串能够匹配由单词组成,那就说明拼接后的字符串也能匹配。这就是动态规划的思想,将一个问题分解成多个小问题,然后采用状态转移方程式来解决问题,dp(s)=dp(i)+dp(s-i),这样我们可以通过记录每一个长度的值,然后从前到后来进行确认,直到最后完整字符串的位置。

var wordBreak = function(s, wordDict) {
    //通过哈希来减少重复和查找时间
    let wordDictSet = new Set(wordDict)
    let len = s.length
    //字典记录过往匹配记录
    let dp = new Array(len+1).fill(false)
    dp[0] = true
    for(let i=0;i<s.length;i++){
        for(let j = 0;j<=i;j++){
            //如果前置字符串匹配并且后续字符串也匹配,确定当前字符串匹配
            if(dp[j]&&wordDictSet.has(s.slice(j,i+1))){
                dp[i+1] = true
                break
            }
        }
    }
    return dp[len]
};