LeetCode--140. Word Break II

2024-04-20 13:18
文章标签 leetcode ii word break 140

本文主要是介绍LeetCode--140. Word Break II,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

问题链接:https://leetcode.com/problems/word-break-ii/

这是紧接着Word Break I的问题,难度上更大,因为要记录所有切分结果所以动态规划的方法就不太奏效了,先复习一下这个问题的算法:dp[i]表示字串0-i是否存在一个切分使得切分后的各个部分都在字典中,状态转移方程为:

                                              j exists in [0,i-1],     make     dp[i]=dp[j] &&   sub[j...i] in dict

这个求dp[i]的子问题与整个问题是一致的。

class Solution {public boolean wordBreak(String s, List<String> wordList){if (s == null || s.length() == 0) return false;int n = s.length();Set<String> set = new HashSet<>();for (String word : wordList) set.add(word);boolean[] dp = new boolean[n];for (int i = 0; i < n; i++)  //外循环是填写dp数组的过程{for (int j = 0; j <= i; j++) //内循环是找符合条件的前缀和存在于字典中的子字符串(前缀串与该子字符串组成当前结尾于i位置的前缀串){String sub = s.substring(j, i + 1);if (set.contains(sub) && (j == 0 || dp[j - 1])){dp[i] = true;break;}}}return dp[n - 1];}
}

再来看Word Break II,可以使用一个数据结构记录下目标字符串S中S[i:j]存在于字典的字串对应的i和j,然后进行搜索拼接。搜索拼接的过程使用深度优先搜索或者while循环可以完成,这里就很类似于https://blog.csdn.net/To_be_to_thought/article/details/86536143中LeetCode--392. Is Subsequence的搜索拼接方法(问题一思路二)

代码如下:

public class WordBreakII {public static List<String> rst;public static List<String> wordBreak(String s, Set<String> wordDict){List<Integer>[] starts = new List[s.length() + 1]; // valid start positions,the index of Array represents end index of substring starting at i that stored in Liststarts[0] = new ArrayList<>();int maxLen = getMaxLen(wordDict);for (int i = 1; i <= s.length(); i++){for (int j = i - 1; j >= i - maxLen && j >= 0; j--){if (starts[j] == null)continue;String word = s.substring(j, i);if (wordDict.contains(word)){if (starts[i] == null){starts[i] = new ArrayList<>();}starts[i].add(j);}}}rst = new ArrayList<>();if (starts[s.length()] == null){return rst;}dfs("", s, starts, s.length());return rst;}private static void dfs(String path, String s, List<Integer>[] starts, int end) {if (end == 0){rst.add(path.substring(1));return;}for (Integer start: starts[end]){String word = s.substring(start, end);dfs(" " + word + path, s, starts, start);}}
}

我在Discussion区域看到了两种不太容易理解的方法,链接https://leetcode.com/problems/word-break-ii/discuss/44243/Java-DP%2BDFS-Memoization%2BDFS-and-DP-Pruning-Solutions-with-Analysis,代码也贴在这里:

public class WordBreakII {public static List<String> rst;public static List<String> wordBreak(String s, Set<String> wordDict){List<Integer>[] starts = new List[s.length() + 1]; // valid start positions,the index of Array represents end index of substring starting at i that stored in Liststarts[0] = new ArrayList<>();int maxLen = getMaxLen(wordDict);for (int i = 1; i <= s.length(); i++){for (int j = i - 1; j >= i - maxLen && j >= 0; j--){if (starts[j] == null)continue;String word = s.substring(j, i);if (wordDict.contains(word)){if (starts[i] == null){starts[i] = new ArrayList<>();}starts[i].add(j);}}}rst = new ArrayList<>();if (starts[s.length()] == null){return rst;}dfs("", s, starts, s.length());return rst;}private static void dfs(String path, String s, List<Integer>[] starts, int end) {if (end == 0){rst.add(path.substring(1));return;}for (Integer start: starts[end]){String word = s.substring(start, end);dfs(" " + word + path, s, starts, start);}}private static int getMaxLen(Set<String> wordDict){int max = 0;for (String s : wordDict){max = Math.max(max, s.length());}return max;}public static HashMap<Integer, List<String>> memo;public static List<String> wordBreak1(String s, Set<String> wordDict){memo = new HashMap<>(); // <Starting index, rst list>return dfs(s, 0, wordDict);}private static List<String> dfs(String s, int start, Set<String> dict){if (memo.containsKey(start)){return memo.get(start);}List<String> rst = new ArrayList<>();if (start == s.length()){rst.add("");return rst;}String curr = s.substring(start);for (String word: dict){if (curr.startsWith(word)){List<String> sublist = dfs(s, start + word.length(), dict);for (String sub : sublist){rst.add(word + (sub.isEmpty() ? "" : " ") + sub);}}}memo.put(start, rst);return rst;}public static List<String> ret;public static List<String> wordBreak2(String s, Set<String> wordDict){ret = new ArrayList<>();if (s == null || s.length() == 0 || wordDict == null){return ret;}//whether a substring starting from position i to the end is breakableboolean[] canBreak = new boolean[s.length()];Arrays.fill(canBreak, true);StringBuilder sb = new StringBuilder();dfs(sb, s, wordDict, canBreak, 0);return ret;}private static void dfs(StringBuilder sb, String s, Set<String> dict, boolean[] canBreak, int start){if (start == s.length()){ret.add(sb.substring(1));return;}if (!canBreak[start]){return;}for (int i = start + 1; i <= s.length(); i++){String word = s.substring(start, i);if (!dict.contains(word))continue;int sbBeforeAdd = sb.length();sb.append(" " + word);int rstBeforeDFS = ret.size();dfs(sb, s, dict, canBreak, i);if (ret.size() == rstBeforeDFS){canBreak[i] = false;}sb.delete(sbBeforeAdd, sb.length());}}public static void main(String[] args){String s="catsanddog";String[] strs={"cat", "cats", "and", "sand", "dog"};Set<String> dict=new HashSet<>();for(String str:strs)dict.add(str);wordBreak(s,dict);List<String> tmp=wordBreak1(s,dict);wordBreak2(s,dict);}
}

 

这篇关于LeetCode--140. Word Break II的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/920360

相关文章

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

leetcode-24Swap Nodes in Pairs

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode swapPairs(L

leetcode-23Merge k Sorted Lists

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode mergeKLists

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

从0到1,AI我来了- (7)AI应用-ComfyUI-II(进阶)

上篇comfyUI 入门 ,了解了TA是个啥,这篇,我们通过ComfyUI 及其相关Lora 模型,生成一些更惊艳的图片。这篇主要了解这些内容:         1、哪里获取模型?         2、实践如何画一个美女?         3、附录:               1)相关SD(稳定扩散模型的组成部分)               2)模型放置目录(重要)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

javascript中break与continue的区别

在javascript中,break是结束整个循环,break下面的语句不再执行了 for(let i=1;i<=5;i++){if(i===3){break}document.write(i) } 上面的代码中,当i=1时,执行打印输出语句,当i=2时,执行打印输出语句,当i=3时,遇到break了,整个循环就结束了。 执行结果是12 continue语句是停止当前循环,返回从头开始。

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param