Algorithm notes - prefix tree, greedy algorithm (updat ing)

1, Prefix tree

1. What is a prefix tree

  • Prefix tree generally refers to dictionary tree, which refers to a structure rather than a class of questions (note that the information is on the way of the tree)

The typical application is to count and sort a large number of strings (but not limited to strings), so it is often used by search engine system for text word frequency statistics. It has the advantages of minimizing unnecessary string comparison and higher query efficiency than hash table.
Trie's core idea is space for time. The common prefix of string is used to reduce the overhead of query time in order to improve efficiency.

  • It has three basic properties
    1) The root node does not contain characters. Except for the root node, each node contains only one character
    2) From the root node to a node, the characters passing through the path are connected to the corresponding string of the node
    3) All child nodes of each node contain different characters

    Taking the above figure as an example, this is a prefix tree, in which nodes are represented by circles, and characters such as "abc" are added to the tree as paths, rather than in the form of nodes. They are all on the road, reused and created if they are available. At the same time, each character starts from the node when adding, so you can see that "abc" and "bck" are two branches, and the first half of "abc" and "abd" are one branch, and finally form two branches.

2. How to generate prefix tree

Here's the code:

  • Data structure representation of nodes
public class TrieTree {
    //Data structure description of points
    public static class TireNode{
        //Add the last point end to the path along the way++
        public int path; When prefixing the tree, how many times has this node arrived and passed
        public int end; Whether this node is the end node of a string, and if so, how many string end nodes is it
        public TireNode[] nexts;//Subordinate Road
        //There are too many types of characters greater than 26. You can use HashMap < char, node > next here. If you want to order, use TreeMap

        public TireNode(){
            path = 0;
            end = 0;
            //Whether a child has a path is indicated by whether the child has a node
            //nexts[0]==null indicates that there is no way to 'a'
            //nexts[0]!=null indicates that there is a way to 'a'
            //nexts[25]!=null indicates that there is a way to 'z
            nexts = new TireNode[26];
        }
    }

    //Data structure of tree
    public static class Trie{
        private TireNode root; //Head node
        //The path value of the root node indicates how many strings you have added (how many strings are prefixed with empty strings)
        public Trie(){
            root = new TireNode();//Expression of head node
        }
        //Add string
        public void insert(String word){
            if (word == null){
                return;
            }
            char[] words = word.toCharArray();//Convert to an array of character types
            TireNode node = root; //Node starts from the root node
            node.path++; //As soon as the root node comes up, there is a way to go. As soon as it comes up, there is a path++
            int index = 0;//Decide which way to go
            for (int i = 0; i < words.length; i++){//Traversal character array
                index = words[i] - 'a';// The character corresponds to which way to go (the index corresponding to a is 0 and b is 1)
                //Next, before judging whether there is a way to go, if there is a node that does not go through if, does not create a new node, and directly jumps to reuse it
                if (node.nexts[index] == null){//Whether the next level road of the current node is an empty node (in fact, whether there is a road to a)
                    node.nexts[index] = new TireNode();//This node has not been created
                }
                node = node.nexts[index];//Move node to child node
                node.path++;//Then pass the new node++
            }
            node.end++; //The end of the last node of the string++
        }

        //delete
        public void delete(String word){
            //First, make sure that word has been added to the tree before, and then delete it
            if (search(word) != 0){
                TireNode node = root;
                char[] chars = word.toCharArray();
                int index = 0;
                //When deleting, add an end to the last node along the path ----
                for (int i = 0; i < chars.length; i++){
                    index = chars[i] - 'a';
                    //If the p value of a node is deleted to 0, all paths in the subsequent sequence are not needed
                    A node in the path information becomes 0 by subtracting one,
                    //It means that the next strings are all the strings to be deleted,
                    //So the following string is set to null directly
                    if (--node.nexts[index].path == 0){
                        node.nexts[index] = null;
                        return;
                    }
                    node = node.nexts[index];
                }
                node.end--;
            }

        }

        //Before querying this word, I added it several times
        public int search(String word){
            if (word == null){
                return 0;
            }
            char[] chars = word.toCharArray();
            TireNode node = root;//Start at the root node
            int index = 0;
            for (int i = 0; i < chars.length; i++){
                index = chars[i] - 'a';
                //I found that there was no way, but there were still characters (for example, I joined abc, but you asked me to check abcdefg. Of course not
                if (node.nexts[index] == null){ //Or I couldn't find it as soon as I came up
                    return 0;
                }
                //If you keep looking
                node = node.nexts[index];
            }
            //After the string is completed, the end here is added several times
            return node.end;
        }

        //Among all the added characters, several are prefixed with the character pre
        public int prefixNumber(String pre){
            if (pre == null){
                return 0;
            }
            char[] pres = pre.toCharArray();
            TireNode node = root;
            int index = 0;
            for (int i = 0; i < pres.length; i++){
                index = pres[i] - 'a';
                if (node.nexts[index] == null){
                    return 0;
                }
                node = node.nexts[index];
            }
            return node.path; //At this time, the returned path is the number of prefixes
        }
    }
}

3. Prefix tree application scenario

3.1 force buckle - key value mapping

  • subject

Implement a MapSum class that supports two methods, insert and sum:
MapSum() initializes the MapSum object
void insert(String key, int val) inserts a key Val key value pair. The string represents the key key and the integer represents the value val. if the key key already exists, the original key value pair will be replaced with a new key value pair.
int sum(string prefix) returns the sum of the values of all key s starting with the prefix prefix

  • solution
public class MapSum {

    private class Node{
        Node [] nexts = new Node[26];
        int val = 0;
    }

    private Node root;
    public MapSum() {
        root = new Node();
    }

    public void insert(String key, int val){
        Node node = root;
        char[] chars = key.toCharArray();
        int index = 0;
        for (int i = 0; i < chars.length; i++){
            index = chars[i] - 'a';
            if (node.nexts[index] == null){
                node.nexts[index] = new Node();
            }
            node = node.nexts[index];
        }
        node.val = val;
    }

    public int sum(String prefix){
        if (prefix == null){
            return 0;
        }
        char[] chars = prefix.toCharArray();
        Node node = root;
        int index = 0;
        for (int i = 0; i < chars.length; i++){
            index = chars[i] - 'a';
            if (node.nexts[index] == null){
                return 0;
            }
            node = node.nexts[index];
        }
        return DFS(node);
    }

    private int DFS(Node node) {
        if (node == null){
            return 0;
        }
        int ans = 0;
        if (node.val > 0){
            ans = node.val;
        }
        for (Node next : node.nexts) {
            ans += DFS(next);
        }
        return ans;
    }
}

(1) Fast retrieval of string
(2) String sorting
(3) Longest common prefix
(4) Auto match prefix display suffix

Tags: Algorithm data structure leetcode greedy algorithm

Posted on Sat, 20 Nov 2021 09:37:06 -0500 by marlonbtx