前缀和 前缀树
实现 Trie (前缀树)
class Trie { class TireNode { boolean isEnd = false; TireNode[] next = new TireNode[26]; TireNode() {} } private TireNode root; /** Initialize your data structure here. */ public Trie() { root = new TireNode(); } /** Inserts a word into the trie. */ public void insert(String word) { TireNode node = root; for (char ch : word.toCharArray()) { if (node.next[ch-'a'] == null) { node.next[ch-'a'] = new TireNode(); } node = node.next[ch-'a']; } node.isEnd = true; } /** Returns if the word is in the trie. */ public boolean search(String word) { TireNode node = root; for (char ch : word.toCharArray()) { if (node.next[ch-'a'] == null) return false; node = node.next[ch-'a']; } return node.isEnd; } /** Returns if there is any word in the trie that starts with the given prefix. */ public boolean startsWith(String prefix) { TireNode node = root; for (char ch : prefix.toCharArray()) { if (node.next[ch-'a'] == null) return false; node = node.next[ch-'a']; } return true; } } /** * Your Trie object will be instantiated and called as such: * Trie obj = new Trie(); * obj.insert(word); * boolean param_2 = obj.search(word); * boolean param_3 = obj.startsWith(prefix); */
添加与搜索单词 - 数据结构设计
回溯那里多注意看看,因为过于依赖之前解数独的写法,犯了一个错误,即每一层都应该是true或者false才是。在循环中要用到if(flashback()) return true,但是循环一结束立马要return fasle。因为还有没有找到的情况呐。这是针对循环的特定写法。如果不是循环的话,直接是return (flashback())。
class WordDictionary { class TireNode { boolean isEnd = false; TireNode[] next = new TireNode[26]; TireNode() {} } private TireNode root; /** Initialize your data structure here. */ public WordDictionary() { root = new TireNode(); } /** Adds a word into the data structure. */ public void addWord(String word) { TireNode node = root; for (char ch : word.toCharArray()) { if (node.next[ch-'a'] == null) { node.next[ch-'a'] = new TireNode(); } node = node.next[ch-'a']; } node.isEnd = true; } /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */ public boolean search(String word) { return searchHelp(word.toCharArray(), 0, root); } private boolean searchHelp(char[] word, int index, TireNode node) { if (node == null) return false; for (int i = index; i < word.length; i++) { char ch = word[index]; if (ch != '.') { //这里就是直接到下一层了。 //开始写成 //if (searchHelp(word, index + 1, node.next[ch-'a'])) return true; //但是这样不行,因为还要加上 else return false; 才算完整。 return (searchHelp(word, index + 1, node.next[ch-'a']); } else { //这里我悟了,每次都要得到false或者true,因为在找不到匹配就false,找到就true。 for (int j = 0; j < 26; j++) { if (searchHelp(word, index + 1, node.next[j])) return true; } return false; } } return node.isEnd; } } /** * Your WordDictionary object will be instantiated and called as such: * WordDictionary obj = new WordDictionary(); * obj.addWord(word); * boolean param_2 = obj.search(word); */
面试题 17.17. 多次搜索
很阴间的一个题目,注意一下ArrayList和数组的转换。
class Solution { class TireNode { int val = -1; TireNode[] next = new TireNode[26]; TireNode() {} } private TireNode root = new TireNode(); private void insert(String word, int val) { TireNode node = root; for (char ch : word.toCharArray()) { if (node.next[ch-'a'] == null) { node.next[ch-'a'] = new TireNode(); } node = node.next[ch-'a']; } node.val = val; } private void search(String word, List<Integer> list) { TireNode node = root; for (char ch : word.toCharArray()) { if (node.next[ch-'a'] == null) return; node = node.next[ch-'a']; if (node.val != -1) list.add(node.val); } } public int[][] multiSearch(String big, String[] smalls) { for (int i = 0; i < smalls.length; i++) { insert(smalls[i], i); } List<List<Integer>> res = new ArrayList<>(); for (int i = 0; i < smalls.length; i++) { res.add(new ArrayList<>()); } for (int i = 0; i < big.length(); i++) { List<Integer>list = new ArrayList<>(); search(big.substring(i), list); for (int x : list) { res.get(x).add(i); } } int[][] result = new int[smalls.length][]; for (int i = 0; i < smalls.length; i++) { result[i] = new int[res.get(i).size()]; for (int j = 0; j < result[i].length; j++) { result[i][j] = res.get(i).get(j); } } return result; } }
区域和检索 - 数组不可变
很基础的前缀和
class NumArray { private int[] presum; public NumArray(int[] nums) { presum = new int[nums.length + 1]; for (int i = 0; i < nums.length; i++) { presum[i + 1] = presum[i] + nums[i]; } } public int sumRange(int i, int j) { return presum[j + 1] - presum[i]; } }
和为K的子数组
前缀和与哈希表,注意哈希表的初始化。其实是对于前缀和下标为0时的初始化。
class Solution { public int subarraySum(int[] nums, int k) { Map<Integer, Integer> map = new HashMap<>(); int count = 0, cur = 0; map.put(0, 1); for (int i = 0; i < nums.length; i++) { cur += nums[i]; if (map.containsKey(cur-k)) { count += map.get(cur-k); } map.put(cur, map.getOrDefault(cur, 0) + 1); } return count; } }
每个元音包含偶数次的最长子字符串
前缀和,位运算,哈希表,也有一点贪心的思想。很棒的一个题。
class Solution { public int findTheLongestSubstring(String s) { String words = "aeiou"; int state = 0, len = 0; Map<Integer, Integer> map = new HashMap<>(); map.put(0, -1); for (int i = 0; i < s.length(); i++) { for (int j = 0; j < words.length(); j++) { if (s.charAt(i) == words.charAt(j)) { state ^= (1 << j); } } if (map.containsKey(state)) { len = Math.max(len, i - map.get(state)); } else { map.put(state, i); } } return len; }
路径总和 III
回溯和前缀和搞在一起,要注意先查找再放入当前的数据。以免放于当前数据后查找时又与当前数据匹配。另外map初始化莫忘,因为root节点前面想要一个0表示从root开始。这里的前缀是加上了当前的数据。
class Solution { private Map<Integer, Integer> map= new HashMap<>(); private int count = 0; public int pathSum(TreeNode root, int sum) { map.put(0, 1); builder(root, sum, 0); return count; } private void builder(TreeNode node, int sum, int pre) { if (node == null) return; int cur = node.val + pre; if (map.containsKey(cur - sum)) { count += map.get(cur - sum); } map.put(cur, map.getOrDefault(cur, 0) + 1); builder(node.left, sum, cur); builder(node.right, sum, cur); map.put(cur, map.get(cur) - 1); } }

浙公网安备 33010602011771号