恢复空格(中等)
2020年7月9日
题目来源:力扣
解题
太难了,天天都是动态规划的题目,状态量和状态转移方程太难想了,参考题解慢慢推敲了
class Solution {
public int respace(String[] dictionary, String sentence) {
Set<String> dict=new HashSet<>(Arrays.asList(dictionary));
int slen=sentence.length();
int[] dp=new int[slen+1];
//dp[i]代表每个字符的最小未识别字符数
for(int i=1;i<=slen;i++){
//下一个字符如果没被匹配,那就最小未识别字符数+1
dp[i]=dp[i-1]+1;
//查看下一个字符加进来是否会与字典相匹配
for(int beg=0;beg<i;beg++){
if(dict.contains(sentence.substring(beg,i)))
dp[i]=Math.min(dp[beg],dp[i]);
}
}
return dp[slen];
}
}
- 用Trie树优化
每次都找字典里是否有匹配的,太浪费时间了,我们可以记住字典里有没有后缀为这个字符的索引,根据索引找识别字符串。
class Solution {
public int respace(String[] dictionary, String sentence) {
// 构建字典树
Trie trie = new Trie();
for (String word: dictionary) {
trie.insert(word);
}
// 状态转移,dp[i] 表示字符串的前 i 个字符的最少未匹配数
int n = sentence.length();
int[] dp = new int[n + 1];
for (int i = 1; i <= n; i++) {
dp[i] = dp[i - 1] + 1;
for (int idx: trie.search(sentence, i - 1)) {
dp[i] = Math.min(dp[i], dp[idx]);
}
}
return dp[n];
}
}
class Trie {
TrieNode root;
public Trie() {
root = new TrieNode();
}
// 将单词倒序插入字典树
public void insert(String word) {
TrieNode cur = root;
for (int i = word.length() - 1; i >= 0; i--) {
int c = word.charAt(i) - 'a';
if (cur.children[c] == null) {
cur.children[c] = new TrieNode();
}
cur = cur.children[c];
}
cur.isWord = true;
}
// 找到 sentence 中以 endPos 为结尾的单词,返回这些单词的开头下标。
public List<Integer> search(String sentence, int endPos) {
List<Integer> indices = new ArrayList<>();
TrieNode cur = root;
for (int i = endPos; i >= 0; i--) {
int c = sentence.charAt(i) - 'a';
if (cur.children[c] == null) {
break;
}
cur = cur.children[c];
if (cur.isWord) {
indices.add(i);
}
}
return indices;
}
}
class TrieNode {
boolean isWord;
TrieNode[] children = new TrieNode[26];
public TrieNode() {}
}