剑指 Offer II 063. 替换单词(648. 单词替换)
题目:
思路:
【1】哈希集合(这种其实更像是暴力破解的方式,通过分割字符进行比对)
【2】字典树(字典树的逻辑研究的话会发现消耗的内存空间相对更少,但是遍历逻辑两者差不多,但是耗费的时间确实天差地别,着实是需要深思的)
代码展示:
字典树优化版本:
//时间10 ms击败79.14% //内存57.6 MB击败55.53% class Solution { class TreeNode{ public boolean isEnd; public char val; public TreeNode[] child; public TreeNode(){ child = new TreeNode[26]; } } public String replaceWords(List<String> dictionary, String sentence) { TreeNode dicTree = new TreeNode(); for(String str : dictionary){ char[] ct = str.toCharArray(); dfs(dicTree, ct, 0); } String[] sarr = sentence.split(" "); for(int i = 0; i < sarr.length; i ++){ sarr[i] = search(sarr[i], dicTree); } StringBuilder sb = new StringBuilder(); for(int i = 0; i < sarr.length; i ++){ if(i != 0){ sb.append(" "); } sb.append(sarr[i]); } return sb.toString(); } public void dfs(TreeNode root, char[] carr, int cur){ if(root.child[carr[cur]-'a'] == null){ root.child[carr[cur]-'a'] = new TreeNode(); } root.child[carr[cur]-'a'].val = carr[cur]; if(cur == carr.length - 1){ root.child[carr[cur]-'a'].isEnd = true; }else{ dfs(root.child[carr[cur]-'a'], carr, cur + 1); } } public String search(String str, TreeNode dicTree){ char[] ct = str.toCharArray(); TreeNode pos = dicTree; int cur = 0; while(pos != null && cur < str.length()){ pos = pos.child[ct[cur++] - 'a']; if(pos != null && pos.isEnd == true){ return str.substring(0,cur); } } return str; } }
字典树的方式:
//时间19 ms击败49.72% //内存61.4 MB击败12.86% //时间复杂度:O(d+s)。其中 d 是 dictionary 的字符数,s 是 sentence 的字符数。 //构建字典树消耗 O(d) 时间,每个单词搜索前缀均消耗线性时间。 //空间复杂度:O(d+s),构建哈希集合消耗 O(d) 空间,分割 sentence 消耗 O(s) 空间。 class Solution { public String replaceWords(List<String> dictionary, String sentence) { Trie trie = new Trie(); for (String word : dictionary) { Trie cur = trie; for (int i = 0; i < word.length(); i++) { char c = word.charAt(i); cur.children.putIfAbsent(c, new Trie()); cur = cur.children.get(c); } cur.children.put('#', new Trie()); } String[] words = sentence.split(" "); for (int i = 0; i < words.length; i++) { words[i] = findRoot(words[i], trie); } return String.join(" ", words); } public String findRoot(String word, Trie trie) { StringBuffer root = new StringBuffer(); Trie cur = trie; for (int i = 0; i < word.length(); i++) { char c = word.charAt(i); if (cur.children.containsKey('#')) { return root.toString(); } if (!cur.children.containsKey(c)) { return word; } root.append(c); cur = cur.children.get(c); } return root.toString(); } } class Trie { Map<Character, Trie> children; public Trie() { children = new HashMap<Character, Trie>(); } }
暴力的方式:
//时间719 ms击败9.58% //内存49.3 MB击败87.36% //时间复杂度:O(d+words.length*word.length)。其中 d 是 dictionary 的字符数,构建哈希集合消耗 O(d) 时间。 //word.length 是 sentence 分割后第 i 个单词的字符数。 //空间复杂度:O(d+s),其中 s 是 sentence 的字符数。构建哈希集合消耗 O(d) 空间,分割 sentence 消耗 O(s) 空间。 class Solution { public String replaceWords(List<String> dictionary, String sentence) { Set<String> dictionarySet = new HashSet<String>(); for (String root : dictionary) { dictionarySet.add(root); } String[] words = sentence.split(" "); for (int i = 0; i < words.length; i++) { String word = words[i]; for (int j = 0; j < word.length(); j++) { if (dictionarySet.contains(word.substring(0, 1 + j))) { words[i] = word.substring(0, 1 + j); break; } } } return String.join(" ", words); } }