前缀和 前缀树

实现 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);
    }
}

 

posted @ 2020-12-12 19:36  CPJ31415  阅读(142)  评论(0)    收藏  举报