文章目录

  • 解法1:回溯 + 记忆数组,记录当前字符串
  • 解法2:回溯 + 记忆数组,记录索引 `i` 到字符结尾的字符串能拆分的组合

https://leetcode-cn.com/problems/word-break-ii/

难度:困难


  给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。

说明:

  • 分隔时可以重复使用字典中的单词。
  • 你可以假设字典中没有重复的单词。

示例 1:

输入:

s = "catsanddog"wordDict = ["cat", "cats", "and", "sand", "dog"]

输出:

["cats and dog","cat sand dog"
]

示例 3:

输入:

s = "catsandog"wordDict = ["cats", "dog", "sand", "and", "cat"]

输出:[]

解法1:回溯 + 记忆数组,记录当前字符串

  拆分单词,我们可以使用回溯法,遍历所有可能的组合。

  对于一个字符串 strs,遍历词典 wordDict 中的所有单词 word,判断这个字符串 strs 是否是以 word 开头,若是,则保存当前单词,并将 strs 中开头的 word 给截去,递归获取单词组合,当 strs 为空时,我们就找到了一个组合。

  如 catsanddog,先找到 cat ,截去后剩余 sanddog ,再找到 sand ,最后剩余 dog

JS 代码:

var wordBreak = function(s, wordDict) {let res = [];let str = [];let len = wordDict.length;const helper = (strs) => {if (strs.length === 0) {res.push(str.slice().join(' '));}let size = strs.length;for (let i = 0; i < len; i++) {let word = wordDict[i];if (strs.startsWith(word)) {str.push(word);helper(strs.substring(word.length, size));str.pop();}}};helper(s);return res;
};

  不过未优化的回溯相当于是暴力解法,效率很低,会在 31 / 36 的用例处超时。

  因此需要使用记忆数组 memo 来优化,说是数组,这边其实是一个 map

  根据我们前面回溯法的思路,每次在递归函数中,我们是对一个字符串 strs 来判断这个字符串是否能被拆分为字典中的单词,这样,若当前字符串 strs 已经递归判断了一次,发现无法被拆分,那么我们下次再遇到这个字符串 strs 时,我们就能直接返回,而不用再继续对其回溯判断是否能被拆分。

  因此对于每个遍历的字符串 strs ,若其在 memo 中的记录为 false ,那么就可以直接返回,节省了剩余的判断时间。

JS 代码:

var wordBreak = function(s, wordDict) {let res = [];let str = [];let memo = new Map();let wordMap = new Set(wordDict);const helper = (strs) => {// 若 strs 已被判断过是无法拆分的,那么直接返回 falseif (memo.get(strs) === false) {return false;}// 若 strs 为空,表示我们的单词拆分成功,记录拆分结果且返回 trueif (strs.length === 0) {res.push(str.slice().join(' '));return true;}let size = strs.length;let flag = false;for (let i = 0; i <= wordDict.length; i++) {let word = wordDict[i];if (strs.startsWith(word)) {str.push(word);// 所有组合情况中,只要有一个能够正确拆分,memo 中的记录就为 trueflag = helper(strs.substring(word.length, size)) || flag;str.pop();}}memo.set(strs, flag);return flag;};helper(s);return res;
};

解法2:回溯 + 记忆数组,记录索引 i 到字符结尾的字符串能拆分的组合

  该思路来自官方解答 。

  假设初始字符串为 pineapplepenapple ,我们已经拆分了一个 pine ,当前字符索引为 4a ,那么从索引 4 到字符串结尾的子串能拆分的组合为 apple pen appleapplepen apple,此时只要再加上一个 pine ,即能获取以单词 pine 开头的所有组合:pine apple pen applepine applepen apple

  memo 保存索引对应的所有组合,memo[4] 中保存的就是 apple pen apple、applepen apple,当第二次递归遍历到这个索引,那么直接返回这个组合就好了。

  这边的字符拆分策略和上一个解法稍有不同,上一个解法中是遍历 wordDict 中的所有字符来判断字符是否在字符串中,这边是遍历整个字符串 strs,从当前索引start 开始先截取一个字符,再截取两个字符…来判断这个字符是否在 wordDict 中出现,若出现,则可以把当前字符与获取的所有拆分单词组合在一起。

JS 代码:

var wordBreak = function(s, wordDict) {let map = new Set(wordDict);let len = s.length;let res = [];let memo = new Map();const getBreakWord = (start) => {// 若前面已得到过已 start 开头到结尾的单词拆分组合,那么直接返回if (memo.has(start)) {return memo.get(start);}let words = [];// 若当前索引位置为字符串结尾,那么表示能正确拆分单词,因此往组合中加入一个空数组,供与最后一个单词组合if (start === len) {words.push([]);}for (let i = start + 1; i <= len; i++) {let word = s.substring(start, i); // 获取子串if (map.has(word)) {let nextWords = getBreakWord(i);// 将当前单词与所有拆分单词组合在一起for (let nextWord of nextWords) {words.push([word, ...nextWord]);}}}memo.set(start, words);return words;};let wordBreaks = getBreakWord(0);for (let arr of wordBreaks) {res.push(arr.join(' '));}return res;
};

LeetCode 140. 单词拆分 II相关推荐

  1. LeetCode 140. 单词拆分 II(DP+回溯)

    1. 题目 给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中.返回所有这些可能的句子. 说明: 分隔时可以重复使 ...

  2. leetcode 140. 单词拆分 II(记忆化)

    给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中.返回所有这些可能的句子. 说明: 分隔时可以重复使用字典中的单 ...

  3. [leetcode] 140. 单词拆分 II

    class Solution {int n;vector<string>res;unordered_map<int,set<int>>hash;string s;v ...

  4. leetcode 140. Word Break II | 140. 单词拆分 II(动态规划)

    题目 https://leetcode.com/problems/word-break-ii/ 题解 由 leetcode 139. Word Break | 139. 单词拆分(动态规划) 改造而来 ...

  5. 【DFS + 记忆化递归】LeetCode 140. Word Break II

    LeetCode 140. Word Break II Solution1:我的答案 纯DFS,在第31个case时超时,还是记录一下.. class Solution { // DFS public ...

  6. Leetcode 139. 单词拆分

    Leetcode 139. 单词拆分 1.问题分析 2.问题解决 3.总结 1.问题分析 题目链接:https://leetcode-cn.com/problems/word-break/   本质上 ...

  7. LeetCode 139. 单词拆分(DP)

    1. 题目 给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词. 说明: 拆分时可以重复使用字典中的单词. 你可以假设字 ...

  8. leetcode - 139. 单词拆分

    139. 单词拆分 -------------------------------------------- 给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以 ...

  9. leetcode: 212. 单词搜索II

    212. 单词搜索II 来源:力扣(LeetCode) 链接: https://leetcode.cn/problems/word-search-ii 给定一个 m x n 二维字符网格 board和 ...

最新文章

  1. 《OpenCV3编程入门》学习笔记1 邂逅OpenCV
  2. ADPRL - 近似动态规划和强化学习 - Note 7 - Approximate Dynamic Programming
  3. 19.7 主动模式和被动模式 添加监控主机 添加自定义模板 处理图形
  4. Quora:人生忠告top10经典摘录,值得分享
  5. cannot import caffe
  6. 【默认加入持久化机制,防止消息丢失,v0.0.3】对RabbitMQ.Client进行一下小小的包装,绝对实用方便...
  7. django 清理缓存,解决manage.py没有clear_cache命令
  8. 批量替换字符串,将其中的数字递增(两种方法)和circlr.js插件的使用
  9. 查看谁连接oracle,oracle如何查看当前有哪些用户连接到数据库
  10. ISO 27001信息安全管理体系认证
  11. 单片机之步进电机驱动篇(一)
  12. STM32F401 / STM32F411 WeAct Studio 资料以及翻版说明
  13. 画图软件修改图片分辨率
  14. Windows配置万德(Wind)量化接口
  15. 【XSY2271】青蛙(栈)
  16. Kubernetes 1.5通过Ceph实现有状态容器
  17. No operations allowed after statement closed
  18. 网站优化SEO技巧分享-企业建立自己的关键词库@运营猫工具箱
  19. ip-guard mac客户端创建方法
  20. jama包-java实现矩阵

热门文章

  1. Premiere做影片时四周的黑框
  2. 高可用 Redis 服务架构分析与搭建
  3. 某大厂程序员吐槽:在北京当码农,不敢结婚不敢生娃,真是注孤生!
  4. 【腾讯三面】你能现场写一下LRU算法吗?
  5. 吊打MySQL,MariaDB到底强在哪?
  6. 之前遇到一位老面试官,问我的问题真的有点东西
  7. 浅谈 UC 国际信息流推荐
  8. MVC已经死了,接下来会发生什么?
  9. 这51个大数据术语,你懂的有几个?
  10. 深度工作,打工人的必备指南!