1. 程式人生 > 遊戲攻略 >《怪物獵人物語2破滅之翼》全屬性三猜基因與裝備搭配

《怪物獵人物語2破滅之翼》全屬性三猜基因與裝備搭配

何為字首樹?如何生成字首樹?

例子:
一個字串型別的陣列arr1,另一個字串型別的陣列arr2。
arr2中有哪些字元,是arr1中出現的?請列印。
arr2中有哪些字元,是作為arr1中某個字串前綴出現的?請列印。
arr2中有哪些字元,是作為arr1中某個字串前綴出現的?請列印arr2中出現次數最大的字首。

字首樹

又稱單詞查詢樹,Trie樹,是一種樹形結構,是一種雜湊樹的變種。 典型應用是用於統計,排序和儲存大量的字串(但不僅限於字串),所以經常被搜尋引擎系統用於文字詞頻統計。 它的優點是:利用字串的公共字首來減少查詢時間,最大限度地減少無謂的字串比較,查詢效率比雜湊樹高。

Trie的核心思想是空間換時間

。利用字串的公共字首來降低查詢時間的開銷以達到提高效率的目的。

字首樹節點

//字首樹節點
    public static class TrieNode {
        public int path;//在加字首樹的時候,這個節點到達過(通過)多少次
        public int end; //這個節點是否是一個字串結尾的節點,如果是的話它是多少個字串結尾的節點
        public TrieNode[] nexts;
        //如果路(字元種類)不止26條,可以以使用HashMap<Char,Node> nexts;演算法一樣,coding細節會有不同
        
//如果希望路與路之間不是像HashMap分散表達,而是連著的,可以使用TreeMap來表示 public TrieNode() { path = 0; end = 0; // nexts[0] == null 沒有走向'a'的路 // nexts[0] != null 有走向'a'的路 // ... // nexts[25] == null 沒有走向'z'的路 // nexts[25] != null 有走向'z'的路
//提前建了26條路,通過看下級有沒有節點就知道後面有沒有路 nexts = new TrieNode[26]; } }

圖解:

根節點上p=4:
1、表示有多少(4)個以空字串為字首的字串
2、表示字首樹中一共有多少(4)個字串
3、若根節點上e=0,表示字首樹中有1個空字串

字首樹相關操作:

package Algorithms;

public class TrieTree {
    //字首樹節點
    public static class TrieNode {
        public int path;//在加字首樹的時候,這個節點到達過(通過)多少次
        public int end; //這個節點是否是一個字串結尾的節點,如果是的話它是多少個字串結尾的節點
        public TrieNode[] nexts;
        //如果路(字元種類)不止26條,可以以使用HashMap<Char,Node> nexts;演算法一樣,coding細節會有不同
        //如果希望路與路之間不是像HashMap分散表達,而是連著的,可以使用TreeMap來表示

        public TrieNode() {
            path = 0;
            end = 0;
            // nexts[0] == null    沒有走向'a'的路
            // nexts[0] != null    有走向'a'的路
            // ...
            // nexts[25] == null   沒有走向'z'的路
            // nexts[25] != null   有走向'z'的路
            //提前建了26條路,通過看下級有沒有節點就知道後面有沒有路
            nexts = new TrieNode[26];
        }
    }

    //字首樹
    public static class Trie {
        private TrieNode root; //新建類的時候會初始化一個根節點

        public Trie() {
            root = new TrieNode();
        }

        public void insert(String word) {
            if (word == null) {
                return;
            }
            char[] chs = word.toCharArray(); //  "abc" -> ['a', 'b', 'c']
            TrieNode node = root; //node從根節點出發
            node.path++; //來到根節點後,path = 1
            int index = 0;
            for (int i = 0; i < chs.length; i++) { //從左往右遍歷字元
                index = chs[i] - 'a'; //由字元,對應走向哪條路  index = 'a'-'a'=0  (把字元轉化為了ASCII碼)
                if (node.nexts[index] == null) { //沒有走向a的路
                    node.nexts[index] = new TrieNode();  //新建節點
                }
                node = node.nexts[index]; //(如果有走向a的路)節點後移
                node.path++;
            }
            node.end++; //來到字串末尾,end++
        }

        //刪除某一個字串:沿途p--,最後一個Node的e--
        //若刪除中發現當前節點的下一節點p值在--之後為0,則將當前節點的下一個節點置空
        public void delete(String word) {
            if (search(word) != 0) { //確定樹中有word才進行刪除操作
                char[] chs = word.toCharArray();
                TrieNode node = root;
                int index = 0;
                for (int i = 0; i < chs.length; i++) {
                    index = chs[i] - 'a';
                    if (--node.nexts[index].path == 0) {//當前節點下級節點的path在--之後變為0
                        node.nexts[index] = null; //把下級節點置空
                        return;
                    }
                    node = node.nexts[index]; //節點後移
                }
                node.end--;
            }
        }

        //查詢word這個字串加入過幾次
        public int search(String word) {
            if (word == null) {
                return 0;
            }
            char[] chs = word.toCharArray();
            TrieNode node = root;
            int index = 0;
            for (int i = 0; i < chs.length; i++) {
                index = chs[i] - 'a';
                if (node.nexts[index] == null) {
                    return 0; //字元沒結束,node結束了:例如有"abcdefg",但沒有"abc"
                }
                node = node.nexts[index];
            }
            return node.end; //字元走完,返回末尾字元節點的end值
        }

        //查詢所有加入的字串中,有幾個是以pre這個字串作為字首的
        public int prefixNumber(String pre) {
            if (pre == null) {
                return 0;
            }
            char[] chs = pre.toCharArray();
            TrieNode node = root;
            int index = 0;
            for (int i = 0; i < chs.length; i++) {
                index = chs[i] - 'a';
                if (node.nexts[index] == null) {
                    return 0;
                }
                node = node.nexts[index];
            }
            return node.path;
        }
    }

    public static void main(String[] args) {
        Trie trie = new Trie();
        System.out.println(trie.search("zuo")); //0
        trie.insert("zuo");
        System.out.println(trie.search("zuo"));  //1
        trie.delete("zuo");
        System.out.println(trie.search("zuo")); //0
        trie.insert("zuo");
        trie.insert("zuo");
        trie.delete("zuo");
        System.out.println(trie.search("zuo")); //1
        trie.delete("zuo");
        System.out.println(trie.search("zuo"));  //0
        trie.insert("zuoa");
        trie.insert("zuoac");
        trie.insert("zuoab");
        trie.insert("zuoad");
        trie.delete("zuoa");
        System.out.println(trie.search("zuoa")); //0
        System.out.println(trie.prefixNumber("zuo"));  //3

    }

}