「前端刷题」139.单词拆分(MEDIUM)

240 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情

题目(Word Break)

链接:https://leetcode-cn.com/problems/word-break
解决数:1702
通过率:52.9%
标签:字典树 记忆化搜索 哈希表 字符串 动态规划 
相关公司:amazon facebook google 

给你一个字符串 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

 

提示:

  • 1 <= s.length <= 300
  • 1 <= wordDict.length <= 1000
  • 1 <= wordDict[i].length <= 20
  • s 和 wordDict[i] 仅有小写英文字母组成
  • wordDict 中的所有字符串 互不相同

思路

解题思路

  • 将题目给的单词存入到Set中,方便取来做比较
  • 题目其实要求的就是找到一个索引位置,能够匹配给定的单词数组
  • 循环对于字符串的每个索引位置都去比较一下,只要此索引位置前面的部分能够匹配单词并且后面剩余的部分拆分依旧能匹配完全即可
  • 从上面的描述听来,满足递归的特性,通过拆分子问题,子问题解决了,当前单词拆分的这个大问题就迎刃而解了

代码

/**
 * @param {string} s
 * @param {string[]} wordDict
 * @return {boolean}
 */
var wordBreak = function (s, wordDict) {
  const size = s.length;
  const set = new Set(wordDict);
  // 备忘录
  let memo = new Array(size);
  /* 函数的定义:判断从start到末尾的子串能否break */
  const dfs = (startIndex) => {
    // s一步步成功划分为单词,才走到越界这步,现在没有剩余子串 所以返回真
    if (startIndex == size) return true;
    // 如果备忘录中有值,直接取了返回不再计算
    if (memo[startIndex] != null) return memo[startIndex];
    for (let i = startIndex + 1; i <= size; i++) {
      // 前缀
      let prefix = s.slice(startIndex, i);
      // 前缀部分是单词且剩余子串能break
      if (set.has(prefix) && dfs(i)) {
        memo[i] = true;
        return true;
      }
      // 如果前缀部分不是单词,就不会执行canBreak(i)。进入下一轮迭代,再切出一个前缀串,再试
    }
    // 指针i怎么划分,都没有返回true,则返回false
    memo[startIndex] = false;
    return false;
  };
  // 从0到末尾的子串能否break
  return dfs(0);
};