A funny way to construct suffix tree and do other things

8/16/2024(.md)

  • algorithm

Outline

  • Problem
  • Algorithm
  • Complexity Analysis
  • Code
  • Example Problems
    • Problem 1

Hello, in this blog I'll share a funny way to construct a suffix tree in O(nlog2⁡n) time, for a given string S of length n. I am going to call the underlying idea the "Leader Split Trick". It can probably be used to solve other problems too.

Problem

A suffix tree of a string S is a radix tree constructed from all the suffixes of S. It's easy to see that it has O(n) nodes. It can be constructed in O(n) using this.

I am going to share a simple and practically useless way of building it in a worse time complexity, O(nlog2⁡n).

Algorithm

Notation
  • When I refer to "suffix i" ahead, I mean the suffix S[i,n].
  • li is the leaf node corresponding to suffix i in the final suffix tree.

Initially, we start with an empty tree (with a virtual root node), and a set G of all suffixes from 1 to n, these suffixes will be stored in the form of their starting index.

It's easy to see that the paths from the root node to lu∀(u∈G) will share some common prefix till an internal node sG, after which these paths will split apart along some downward edges of the internal node. Let's define dG to be the longest common prefix across the paths (root,lu)∀u∈G.

Our algorithm will essentially do the following:

  1. Find dG.
  2. Split apart G into disjoint subsets G′ (each subset G′ will have suffixes whose leaves lie in the subtree of a unique child node of sG).
  3. Solve the problem recursively for each subset, and add an edge in the suffix tree from sG to sG′ for every G′.

Now, we define a recursive function f(G,L,dep,dis).

Definitions
  • G : a set of suffixes (represented by starting indices)
  • L : "leader" element (possibly undefined, in which case it will be "null")
  • dep : depth of sGp (the internal node of the parent call).
  • dis : sorted list of integers (possibly undefined).

In each call, f(G,L,dep,dis), we do the following:

  1. If the "Leader" element L is undefined:
    1. Set L to a random element of G.
    2. For every suffix i∈G, find dis[i], the longest common prefix of the suffixes i and L. This can be done in O(|G|⋅log⁡n) using binary search + hashing. We store dis in a sorted manner.
  2. Let m be the minimum value in dis[]. It's easy to see that the internal node created from splitting G will occur at depth dep+m. We create sG, and add an edge corresponding to the substring S[L+dep+1,L+dep+m] from sGp to sG.
  3. Now, we delete all suffixes i∈G:dis[i]=m, from G (and their corresponding elements from dis), and group them into disjoint subsets based on the character Si+dep+m+1 for suffix i (basically the next character after the internal node).
  4. We call f(G′,null,dep+m,null) for every newly created subset G′, and also call f(G,L,dep + m,dis) for the modified subset G.

Note: There might be some off-by-one errors.

Complexity Analysis

Consider the following problem:

We have n singleton sets, and are given some set merge operations. When merging sets A and B, we merge B to A with probability |A||A|+|B| and A to B with the probability |B||A|+|B|.

The above problem is computationally equivalent to Randomized Quicksort, which has an expected time complexity of O(nlog⁡n).

It's not difficult to see that our split operations are simply the operations that will occur in the above problem in a reversed manner (Formally, we can define a bijective relationship between the two sets of operations, such that related sets of operations will occur with the same probability) . Therefore, the time taken by all the split operations is O(nlog⁡n).

However, every time we perform a split operation (merge in reverse), we also compute dis for the child set C (which gets merged into the parent set), and that takes O(|C|log⁡n) time. Thus, our entire algorithm has an expected time complexity of O(nlog2⁡n).

Code

My implementation can be found here.

Example Problems

Problem 1

You are given a tree on n nodes. You also have a set containing all nodes, {1,2,…,n}. You have to process the following queries online:

  1. "1mxv1v2…vx" : Remove the nodes v1,v2…,vx from the set S whose maximum element is m, and create a new set with these elements (it is guaranteed that there exists some set with maximum element m and vi∈S∀i).
  2. "2m" : Let the set whose maximum element is m be S. Find some node x∈S∣maxy∈Sdis(x,y)=maxu,v∈Sdis(u,v).
Solution
[to be updated]