140.WordBreakII

编程

Note:

  • The same word in the dictionary may be reused multiple times in the segmentation.
  • You may assume the dictionary does not contain duplicate words.

Example 1:

Input:

s = "catsanddog"

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

Output:

[

  "cats and dog",

  "cat sand dog"

]

Example 2:

Input:

s = "pineapplepenapple"

wordDict = ["apple", "pen", "applepen", "pine", "pineapple"]

Output:

[

  "pine apple pen apple",

  "pineapple pen apple",

  "pine applepen apple"

]

Explanation: Note that you are allowed to reuse a dictionary word.

Example 3:

Input:

s = "catsandog"

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

Output:

[]

解题思路

这道题的解法其实跟139. Word Break一样,可以参考139. Word Break的思路 https://my.oschina.net/JiamingMai/blog/4331735 ,与139. Word Break稍有不同的是,这道题需要在此基础上将h[0][i]为true的所有情况记录起来。

时间复杂度分析

本质与139. Word Break一样,所以时间复杂度也是O(kn^2),分析过程参考 https://my.oschina.net/JiamingMai/blog/4331735

最终实现

Java 实现

public class Solution {

List<String>[] records;

private boolean[][] h;

private boolean[][] r;

public List<String> wordBreak(String s, List<String> wordDict) {

int n = s.length();

if (!fastWordBreakInternal(s, wordDict)) {

return new ArrayList<>();

}

boolean res = wordBreakInternal(s, wordDict);

if (res) {

return records[n];

}

return new ArrayList<>();

}

public boolean fastWordBreakInternal(String s, List<String> wordDict) {

int n = s.length();

h = new boolean[n+1][n+1];

r = new boolean[n+1][n+1];

initR(n, s, wordDict);

h[0][0] = true;

for (int i = 1; i <= n; i++) {

for (int j = i; j >= 0; j--) {

if (!h[0][i]) {

h[0][i] = h[0][i-j] && r[i-j][i];

} else {

break;

}

}

}

return h[0][n];

}

public boolean wordBreakInternal(String s, List<String> wordDict) {

int n = s.length();

h = new boolean[n + 1][n + 1];

r = new boolean[n + 1][n + 1];

records = new List[n + 1];

initR(n, s, wordDict);

h[0][0] = true;

for (int i = 1; i <= n; i++) {

for (int j = i; j >= 0; j--) {

if (h[0][i - j] && r[i - j][i]) {

h[0][i] = true;

record(i, j, s);

}

}

}

return h[0][n];

}

private void record(int i, int j, String s) {

if (null == records[i]) {

records[i] = new ArrayList<>();

}

String token = s.substring(i - j, i);

if (null != records[i - j]) {

for (String str : records[i - j]) {

StringBuffer sb = new StringBuffer();

sb.append(str).append(" ").append(token);

records[i].add(sb.toString());

}

} else {

records[i].add(token);

}

}

private void initR(int n, String s, List<String> wordDict) {

for (int i = 0; i <= n; i++) {

for (int j = i; j <= n; j++) {

r[i][j] = r(i, j, s, wordDict);

}

}

}

private boolean r(int i, int j, String s, List<String> wordDict) {

String token = s.substring(i, j);

for (String word : wordDict) {

if (word.equals(token)) {

return true;

}

}

return false;

}

public static void main(String[] args) {

List<String> wordDict = new ArrayList<>();

wordDict.add("a");

wordDict.add("aa");

wordDict.add("aaa");

wordDict.add("aaaa");

wordDict.add("aaaaa");

wordDict.add("aaaaaa");

wordDict.add("aaaaaaa");

wordDict.add("aaaaaaaa");

wordDict.add("aaaaaaaaa");

wordDict.add("aaaaaaaaaa");

String s = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

Solution solution = new Solution();

List<String> res = solution.wordBreak(s, wordDict);

res.stream().forEach(str -> {System.out.println(str);});

}

}

注意到代码main方法里面的那个例子,输入是一大串连续的a只有中间一个b,这种情况如果直接边算边记录的话会超时,所以这里有个trick就是先快速判断输入的字符串能否拆解,如果不能就直接输出一个空的List即可,这个例子正好就是不能拆解的case。

以上是 140.WordBreakII 的全部内容, 来源链接: utcz.com/z/517997.html

回到顶部