Multiple Patterns Searching - Suffix Tree


Pattern Searching | Set 8 (Suffix Tree Introduction) | GeeksforGeeks
Given a text txt[0..n-1] and a pattern pat[0..m-1], write a function search(char pat[], char txt[]) that prints all occurrences of pat[] in txt[]. You may assume that n > m.
Preprocess Pattern or Preoprocess Text?
We have discussed the following algorithms in the previous posts:
All of the above algorithms preprocess the pattern to make the pattern searching faster. The best time complexity that we could get by preprocessing pattern is O(n) where n is length of the text. In this post, we will discuss an approach that preprocesses the text. A suffix tree is built of the text. After preprocessing text (building suffix tree of text), we can search any pattern in O(m) time where m is length of the pattern.
Imagine you have stored complete work of William Shakespeare and preprocessed it. You can search any string in the complete work in time just proportional to length of the pattern. This is really a great improvement because length of pattern is generally much smaller than text.
Preprocessing of text may become costly if the text changes frequently. It is good for fixed text or less frequently changing text though.
A Suffix Tree for a given text is a compressed trie for all suffixes of the given text. We have discussed Standard Trie. Let us understand Compressed Trie with the following array of words


Build suffix tree from search text(not from pattern).
A Suffix Tree for a given text is a compressed trie for all suffixes of the given text.
How to build a Suffix Tree for a given text?
1) Generate all suffixes of given text.
2) Consider all suffixes as individual words and build a compressed trie.
A Suffix Tree for a given text is a compressed trie for all suffixes of the given text

How to build a Suffix Tree for a given text?
Following are all suffixes of “banana\0″
banana\0
anana\0
nana\0
ana\0
na\0
a\0
\0
If we consider all of the above suffixes as individual words and build a trie, we get following.
If we join chains of single nodes, we get the following compressed trie, which is the Suffix Tree for given text “banana\0″
How to search a pattern in the built suffix tree?
1) Starting from the first character of the pattern and root of Suffix Tree, do following for every character.
…..a) For the current character of pattern, if there is an edge from the current node of suffix tree, follow the edge.
…..b) If there is no edge, print “pattern doesn’t exist in text” and return.
2) If all characters of pattern have been processed, i.e., there is a path from root for characters of the given pattern, then print “Pattern found”.
Let us consider the example pattern as “nan” to see the searching process. Following diagram shows the path followed for searching “nan” or “nana”.
How does this work?
Every pattern that is present in text (or we can say every substring of text) must be a prefix of one of all possible suffixes. The statement seems complicated, but it is a simple statement, we just need to take an example to check validity of it.


Code:
https://www.ideserve.co.in/learn/pattern-matching-using-trie

    
// we are only dealing with keys with chars 'a' to 'z'
    final static int ALPHABET_SIZE = 26;
    final static int NON_VALUE = -1;
     
    class TrieNode
    {
         
        ArrayList<Integer> endingIndices;
        TrieNode[] children;
         
        TrieNode(boolean isLeafNode, int value)
        {
            children = new TrieNode[ALPHABET_SIZE];
            this.endingIndices = new ArrayList();
        }
    }
 
    TrieNode root;
    TrieForPatternMatching()
    {
        this.root = new TrieNode(false, NON_VALUE);
    }
 
    private int getIndex(char ch)
    {
        return ch - 'a';
    }
 
    public void insert(String key, int offset)
    {
        // null keys are not allowed
        if (key == null) return;
         
        key = key.toLowerCase();
         
        TrieNode currentNode = this.root;
        int charIndex = 0;
         
        while (charIndex < key.length())
        {
            int childIndex = getIndex(key.charAt(charIndex));
 
            if (childIndex < 0 || childIndex >= ALPHABET_SIZE)
            {
                System.out.println("Invalid Key");
                return;
            }
             
            if (currentNode.children[childIndex] == null)
            {
                currentNode.children[childIndex] = new TrieNode(false, NON_VALUE);
            }
             
            currentNode = currentNode.children[childIndex];
             
            // add index for this alphabet where it ends in the string
            currentNode.endingIndices.add(charIndex + offset);
             
            charIndex  += 1;
        }
         
    }
     
 
 
    private  void matchAndPrintPattern(String str)
    {
        if (str == null) return;
         
        TrieNode currentNode = root;
        int charIndex = 0;
         
        while ((charIndex < str.length()))
        {
            if (currentNode == null) break;
 
            currentNode = currentNode.children[getIndex(str.charAt(charIndex))];
 
            charIndex += 1;
        }
 
        if (charIndex < str.length())
        {
            System.out.println("Pattern does not exist.");
        }
        else
        {
            System.out.println("Pattern found in text starting at following indices..");
            for (int i = 0; i < currentNode.endingIndices.size(); i++)
            {
                System.out.print(currentNode.endingIndices.get(i) - (str.length() - 1));
                System.out.print(",");
            }
        }
        return;
    }
 
    private  void generateAndInsertSuffixes(String text)
    {
        for (int i = 0; i < text.length(); i++)
        {
            this.insert(text.substring(i), i);
        }
    }
 
    public void printPatternMatches(String text, String pattern)
    {
        generateAndInsertSuffixes(text);
        matchAndPrintPattern(pattern);
    }
http://massivealgorithms.blogspot.com/2015/07/cc150v4-208-full-text-search-suffix.html
 // 后缀树节点
 static class SuffixTreeNode {
  HashMap<Character, SuffixTreeNode> children = new HashMap<Character, SuffixTreeNode>();

  char value;
  ArrayList<Integer> indexes = new ArrayList<Integer>();

  public SuffixTreeNode() {
  }

  public void insertString(String s, int index) {
   indexes.add(index);
   if (s != null && s.length() > 0) {
    value = s.charAt(0);
    SuffixTreeNode child = null;
    if (children.containsKey(value)) {
     child = children.get(value);
    } else {
     child = new SuffixTreeNode();
     children.put(value, child);
    }
    String remainder = s.substring(1);
    child.insertString(remainder, index);
   }
  }

  public ArrayList<Integer> search(String s) {
   if (s == null || s.length() == 0) {
    return indexes;
   } else {
    char first = s.charAt(0);
    if (children.containsKey(first)) {
     String remainder = s.substring(1);
     return children.get(first).search(remainder);
    }
   }
   return null;
  }
 }

 // 后缀树
 static class SuffixTree {
  SuffixTreeNode root = new SuffixTreeNode();

  public SuffixTree(String s) {
   for (int i = 0; i < s.length(); i++) {
    String suffix = s.substring(i);
    root.insertString(suffix, i);
   }
  }

  public ArrayList<Integer> search(String s) {
   return root.search(s);
  }
 }
http://blog.csdn.net/at8008/arWticle/details/17256321
构造S的后缀树 - O(ns^2)
1. 后缀树类, 后缀树存了字符串S所有的后缀
public class SuffixTreeNode {
 // 当前root的孩子们
 // 若为英语小写字母,则最多有26个孩子
 HashMap<Character, SuffixTreeNode> children 
        = new HashMap<Character, SuffixTreeNode>();
 
 char value; // 当前节点的值
 
 // 存该后缀出现的起始位置,即多模式查找的结果
 // exp: S = bibs, T = b, 则 节点b的 indexes = [0,3]
 ArrayList<Integer> indexes = new ArrayList<Integer>();
 
 public SuffixTreeNode(){}
 
 public void insertString(String s, int index){
  indexes.add(index);  // 添加当前index
  if(s != null && s.length() > 0){
   value = s.charAt(0);
   SuffixTreeNode child = null;
   // 若root已经有这个value的孩子了,则将后缀附加到这个子节点树上
   if(children.containsKey(value)){
    child = children.get(value);
   }else{
    child = new SuffixTreeNode();
    children.put(value, child);
   }
   String remainder = s.substring(1);
   // 递归添加后缀
   child.insertString(remainder, index);
   
  }
 }
 
 public ArrayList<Integer> search(String s){
  if(s == null || s.length() == 0)
   return indexes;
  else{
   char first = s.charAt(0);
   if(children.containsKey(first)){
    String remainder = s.substring(1);
    return children.get(first).search(remainder);
   }
  }
  return null;
 }
}


Applications of Suffix Tree
1) Pattern Searching
1) Starting from the first character of the pattern and root of Suffix Tree, do following for every character.
…..a) For the current character of pattern, if there is an edge from the current node of suffix tree, follow the edge.
…..b) If there is no edge, print “pattern doesn’t exist in text” and return.
2) If all characters of pattern have been processed, i.e., there is a path from root for characters of the given pattern, then print “Pattern found”.
2) Finding the longest repeated substring
3) Finding the longest common substring
The longest common substrings of a set of strings can be found by building a generalised suffix tree for the strings, and then finding the deepest internal nodes which have leaf nodes from all the strings in the subtree below it.

The figure is the suffix tree for the strings "ABAB", "BABA" and "ABBA".

If the suffix tree is prepared for constant time lowest common ancestor retrieval, it can be solved in O(N) time.

4) Finding the longest palindrome in a string

Ukkonen’s Suffix Tree Construction is discussed in following articles: - O(n)
Ukkonen’s Suffix Tree Construction – Part 1
Ukkonen’s Suffix Tree Construction – Part 2
Ukkonen’s Suffix Tree Construction – Part 3
Ukkonen’s Suffix Tree Construction – Part 4
Ukkonen’s Suffix Tree Construction – Part 5
Ukkonen’s Suffix Tree Construction – Part 6

X. Suffix Tree Application 2 – Searching All Patterns
https://www.geeksforgeeks.org/suffix-tree-application-2-searching-all-patterns/


Read full article from Pattern Searching | Set 8 (Suffix Tree Introduction) | GeeksforGeeks

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts