• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
neverlandly
博客园    首页    新随笔    联系   管理    订阅  订阅

Leetcode: Word Break II

Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word.

Return all such possible sentences.

For example, given
s = "catsanddog",
dict = ["cat", "cats", "and", "sand", "dog"].

A solution is ["cats and dog", "cat sand dog"].

难度:98,参考了别人的思路:这道题目要求跟Word Break比较类似,不过返回的结果不仅要知道能不能break,如果可以还要返回所有合法结果。一般来说这种要求会让动态规划的效果减弱很多,因为我们要在过程中记录下所有的合法结果,中间的操作会使得算法的复杂度不再是动态规划的两层循环,因为每次迭代中还需要不是constant的操作,最终复杂度会主要取决于结果的数量,而且还会占用大量的空间,因为不仅要保存最终结果,包括中间的合法结果也要一一保存,否则后面需要历史信息会取不到。所以这道题目我们介绍两种方法,一种是直接brute force用递归解,另一种是跟Word Break思路类似的动态规划。

类似word break中的DP做法,其实就是在word break的基础上稍作修改:

 1 public class Solution {
 2     public List<String> wordBreak(String s, List<String> wordDict) {
 3         if (s == null || s.length() == 0) return null;
 4         List<List<String>> results = new ArrayList<>();
 5 
 6         HashSet<String> dict = new HashSet<>();
 7         for (String word : wordDict) {
 8             dict.add(word);
 9         }
10         boolean[] res = new boolean[s.length()+1];
11         res[0] = true;
12         results.add(new ArrayList<String>());
13         results.get(0).add("");
14         
15         for (int i=1; i<=s.length(); i++) {
16             results.add(new ArrayList<String>());
17             for (int j=0; j<i; j++) {
18                 if (res[j]) {
19                     String str = s.substring(j, i);
20                     if (dict.contains(str)) {
21                         res[i] = true;
22                         for (String kk : results.get(j)) {
23                             if (kk.length() == 0)
24                                 results.get(i).add(str);
25                             else
26                                 results.get(i).add(kk + " " + str);
27                         }
28                     }
29                 }
30 
31             }
32         }
33         return results.get(s.length());
34     }
35 }

 

还有一点需要指出的是,这个代码放到LeetCode中会MLE,但是面试应该够了,原因是LeetCode中有一个非常tricky的测试case,

Because the existence of test case 'aaaaa...aaaab', ['a', 'aa', 'aaa', ... 'aaa...aa'], the forward DP solution will cause MLE while the backward DP is just fine, apparently the test case 'baaaaaaaa...aaaa', ['a', 'aa', 'aaa', ..., 'aaa...aa'] should also be included.

 

有时间的话,研究一下vote最高的做法, refer to: https://discuss.leetcode.com/topic/27855/my-concise-java-solution-based-on-memorized-dfs

Solution based on memorized DFS (Top- Down recursion), whereas my approache above is bottom-up recursion and with memorization

Using DFS directly will lead to TLE, so I just used HashMap to save the previous results to prune duplicated branches, as the following:

 1 public List<String> wordBreak(String s, Set<String> wordDict) {
 2     return DFS(s, wordDict, new HashMap<String, LinkedList<String>>());
 3 }       
 4 
 5 // DFS function returns an array including all substrings derived from s.
 6 List<String> DFS(String s, Set<String> wordDict, HashMap<String, LinkedList<String>>map) {
 7     if (map.containsKey(s)) 
 8         return map.get(s);
 9         
10     LinkedList<String>res = new LinkedList<String>();     
11     if (s.length() == 0) {
12         res.add("");
13         return res;
14     }               
15     for (String word : wordDict) {
16         if (s.startsWith(word)) {
17             List<String>sublist = DFS(s.substring(word.length()), wordDict, map);
18             for (String sub : sublist) 
19                 res.add(word + (sub.isEmpty() ? "" : " ") + sub);               
20         }
21     }       
22     map.put(s, res);
23     return res;
24 }

 

posted @ 2014-09-14 11:21  neverlandly  阅读(933)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3