单词拆分

方法 1:暴力
算法
最简单的实现方法是用递归和回溯。为了找到解,咱们能够检查字典单词中每个单词的可能前缀,若是在字典中出现过,那么去掉这个前缀后剩余部分回归调用。同时,若是某次函数调用中发现整个字符串都已经被拆分且在字典中出现过了,函数就返回 true 。算法

public boolean wordBreak(String s, List<String> wordDict) { return word_Break(s, new HashSet(wordDict), 0); } public boolean word_Break(String s, Set<String> wordDict, int start) { if (start == s.length()) { return true; } for (int end = start + 1; end <= s.length(); end++) { if (wordDict.contains(s.substring(start, end)) && word_Break(s, wordDict, end)) { return true; } } return false; }

方法 2:记忆化回溯
算法数组

在先前的方法中,咱们看到许多函数调用都是冗余的,也就是咱们会对相同的字符串调用屡次回溯函数。为了不这种状况,咱们可使用记忆化的方法,其中一个 memomemo 数组会被用来保存子问题的结果。每当访问到已经访问过的后缀串,直接用 memomemo 数组中的值返回而不须要继续调用函数。函数

经过记忆化,许多冗余的子问题能够极大被优化,回溯树获得了剪枝,所以极大减少了时间复杂度。优化

public boolean wordBreak(String s, List<String> wordDict) { return word_Break(s, new HashSet(wordDict), 0, new Boolean[s.length()]); } public boolean word_Break(String s, Set<String> wordDict, int start, Boolean[] memo) { if (start == s.length()) { return true; } if (memo[start] != null) { return memo[start]; } for (int end = start + 1; end <= s.length(); end++) { if (wordDict.contains(s.substring(start, end)) && word_Break(s, wordDict, end, memo)) { return memo[start] = true; } } return memo[start] = false; }

方法 3:使用动态规划

算法spa

这个方法的想法是对于给定的字符串(s)能够被拆分红子问题 s1 和 s2 。若是这些子问题均可以独立地被拆分红符合要求的子问题,那么整个问题 s 也能够知足。也就是,若是 "catsanddog" 能够拆分红两个子字符串 "catsand" 和 "dog" 。子问题 "catsand" 能够进一步拆分红 "cats" 和 "and" ,这两个独立的部分都是字典的一部分,因此 "catsand" 知足题意条件,再往前, "catsand" 和 "}dog" 也分别知足条件,因此整个字符串 "catsanddog" 也知足条件。指针

如今,咱们考虑 dp 数组求解的过程。咱们使用 n+1大小数组的dp ,其中 n 是给定字符串的长度。咱们也使用 2 个下标指针 i 和 j ,其中 i 是当前字符串从头开始的子字符串(s')的长度, j 是当前子字符串(s')的拆分位置,拆分红 s'(0,j)和 s'(j+1,i)code

为了求出 \text{dp}dp 数组,咱们初始化dp[0] 为true ,这是由于空字符串老是字典的一部分。 dp 数组剩余的元素都初始化为 falseblog

咱们用下标 i 来考虑全部从当前字符串开始的可能的子字符串。对于每个子字符串,咱们经过下标 j 将它拆分红 s1' 和 s2' (注意 i 如今指向 s2' 的结尾)。为了将dp[i] 数组求出来,咱们依次检查每一个 dp[j] 是否为 true,也就是子字符串 s1' 是否知足题目要求。若是知足,咱们接下来检查 s2' 是否在字典中。若是包含,咱们接下来检查 s2' 是否在字典中,若是两个字符串都知足要求,咱们让 dp[i] 为 true ,不然令其为false递归

public boolean wordBreak(String s, List<String> wordDict) { Set<String> wordDictSet=new HashSet(wordDict); boolean[] dp = new boolean[s.length() + 1]; dp[0] = true; for (int i = 1; i <= s.length(); i++) { for (int j = 0; j < i; j++) { if (dp[j] && wordDictSet.contains(s.substring(j, i))) { dp[i] = true; break; } } } return dp[s.length()]; }
相关文章
相关标签/搜索