哦,不!你不小心把一个长篇文章中的空格、标点都删掉了,并且大写也弄成了小写。像句"I reset the computer. It still didn’t boot!"已经变成了"iresetthecomputeritstilldidntboot"。在处理标点符号和大小写之前,你得先把它断成词语。当然了,你有一本厚厚的词典dictionary,不过,有些词没在词典里。假设文章用sentence表示,设计一个算法,把文章断开,要求未识别的字符最少,返回未识别的字符数。
注意: 本题相对原题稍作改动,只需返回未识别的字符数
示例:
1 2 3 4 5 输入: dictionary = ["looked","just","like","her","brother"] sentence = "jesslookedjustliketimherbrother" 输出: 7 解释: 断句后为"jess looked just like tim her brother",共7个未识别字符。
提示:
0 <= len(sentence) <= 1000
dictionary中总字符数不超过 150000。
你可以认为dictionary和sentence中只包含小写字母。
来源:力扣(LeetCode) 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解: 本题直接借鉴官方题解,就是字符串+动态规划,其他的方法都不够通俗易懂。基本思想就是,用一个 dp 数组存储前i个字符中最少未识别的字符的数量,定义两个指针i,j,判断 sentence 中 j-1 到 i-1 的子串是否在 dictionary 中,如果在 dictionary 中,那么状态转移方程为 $dp[i]=min(dp[i], dp[j-1])$ ;如果不存在,状态转移方程为$dp[i]=dp[i-1]+1$,即为前 i-1 个未识别的字符数量,加上当前 i 结点的一个字符。
关于如何存储 dictionary 中的单词,由于暴力破解每次都需要重复遍历,浪费了大量的时间,所以这里官方采用 Trie (字典树) 来存储字典中的单词,将单词的每个字母逆序插入到字典树中,每次状态转移的时候就从 Trie 的根节点出发,如果 sentence[j] 在 Trie 没有出现,则 sentence[j…i-1] 不在字典中,否则需要判断该字串是不是 dictionary 中的一个单词,通过加入 isEnd 标记来判断是否成词。
具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 class Solution { public int respace (String[] dictionary, String sentence) { int len = sentence.length(); Trie root = new Trie(); for (String word : dictionary) { root.buildTrie(word); } int [] dp = new int [len + 1 ]; Arrays.fill(dp, Integer.MAX_VALUE); dp[0 ] = 0 ; for (int i = 1 ; i <= len; i++) { dp[i] = dp[i - 1 ] + 1 ; Trie curr = root; for (int j = i; j >= 1 ; j--) { int t = sentence.charAt(j - 1 ) - 'a' ; if (curr.next[t] == null ) break ; if (curr.next[t].isEnd == true ) dp[i] = Math.min(dp[i], dp[j - 1 ]); curr = curr.next[t]; } } return dp[len]; } } class Trie { public Trie[] next; public boolean isEnd; public Trie () { next = new Trie[26 ]; isEnd = false ; } public void buildTrie (String s) { Trie currentPoints = this ; for (int i = s.length() - 1 ; i >= 0 ; i--) { int temp = s.charAt(i) - 'a' ; if (currentPoints.next[temp] == null ) currentPoints.next[temp] = new Trie(); currentPoints = currentPoints.next[temp]; } currentPoints.isEnd = true ; } }