解法一:直接DP

参考链接:https://leetcode-cn.com/problems/re-space-lcci/solution/jian-dan-dp-trieshu-bi-xu-miao-dong-by-sweetiee/ 解法一

  1. import java.util.HashSet;
  2. import java.util.Set;
  3. class Solution {
  4. public int respace(String[] dictionary, String sentence) {
  5. Set<String> dictionatySet = new HashSet<>(dictionary.length);
  6. for (String str : dictionary) {
  7. dictionatySet.add(str);
  8. }
  9. int len = sentence.length();
  10. int[] dp = new int[len + 1];
  11. for (int i = 1; i <= len; ++i) {
  12. dp[i] = dp[i - 1] + 1;
  13. for (int j = 0; j < i; ++j) {
  14. if (dictionatySet.contains(sentence.substring(j, i))) {
  15. dp[i] = Math.min(dp[i], dp[j]);
  16. }
  17. }
  18. }
  19. return dp[len];
  20. }
  21. }

解法二:Trie加速查询

参考链接:https://leetcode-cn.com/problems/re-space-lcci/solution/jian-dan-dp-trieshu-bi-xu-miao-dong-by-sweetiee/ 解法二

  1. import java.util.*;
  2. class Solution {
  3. public int respace(String[] dictionary, String sentence) {
  4. Trie trie = new Trie();
  5. for (String str : dictionary) {
  6. StringBuilder stringBuilder = new StringBuilder(str);
  7. trie.add(stringBuilder.reverse().toString());
  8. }
  9. int len = sentence.length();
  10. int[] dp = new int[len + 1];
  11. for (int i = 1; i <= len; ++i) {
  12. dp[i] = dp[i - 1] + 1;
  13. for (int j : trie.search(sentence, i - 1)) {
  14. dp[i] = Math.min(dp[i], dp[j]);
  15. }
  16. }
  17. return dp[len];
  18. }
  19. }
  20. /**
  21. * 字典树, 以实现基本的增删查操作
  22. */
  23. class Trie {
  24. /**
  25. * 根结点
  26. */
  27. private Node root;
  28. /**
  29. * 单词数量
  30. */
  31. private int size;
  32. public Trie() {
  33. root = new Node();
  34. }
  35. /**
  36. * 添加单词
  37. *
  38. * @param word 单词
  39. */
  40. public void add(String word) {
  41. Node p = root;
  42. for (char ch : word.toCharArray()) {
  43. if (p.next.get(ch) == null) {
  44. p.next.put(ch, new Node());
  45. }
  46. p = p.next.get(ch);
  47. }
  48. // 该节点上没有单词则加上单词
  49. // 防止相同单词重复添加
  50. if (!p.isWord) {
  51. p.isWord = true;
  52. ++size;
  53. }
  54. }
  55. /**
  56. * 查询在s中以end下标为字符串结尾的子串且它在Trie中
  57. *
  58. * @param s 源字符串
  59. * @param end 结尾字符下标
  60. * @return 符合条件的单词数组
  61. */
  62. public List<Integer> search(String s, int end) {
  63. List<Integer> ans = new LinkedList<>();
  64. Node p = root;
  65. for (int i = end; i >= 0; --i) {
  66. char ch = s.charAt(i);
  67. if (p.next.get(ch) == null) {
  68. break;
  69. }
  70. p = p.next.get(ch);
  71. if (p.isWord) {
  72. ans.add(i);
  73. }
  74. }
  75. return ans;
  76. }
  77. }
  78. /**
  79. * 字符结点
  80. */
  81. class Node {
  82. /**
  83. * 当前结点是否为某个单词的结尾
  84. */
  85. public boolean isWord;
  86. /**
  87. * 用Map存储子结点
  88. */
  89. public Map<Character, Node> next;
  90. public Node() {
  91. next = new HashMap<>();
  92. }
  93. public Node(boolean isWord) {
  94. this.isWord = isWord;
  95. }
  96. }