JavaScript使用騰訊地圖API方法
阿新 • • 發佈:2021-08-11
何為字首樹?如何生成字首樹?
例子:
一個字串型別的陣列arr1,另一個字串型別的陣列arr2。
arr2中有哪些字元,是arr1中出現的?請列印。
arr2中有哪些字元,是作為arr1中某個字串前綴出現的?請列印。
arr2中有哪些字元,是作為arr1中某個字串前綴出現的?請列印arr2中出現次數最大的字首。
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 } }