Open In App

­­kasai’s Algorithm for Construction of LCP array from Suffix Array

Last Updated : 06 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Background Suffix Array : A suffix array is a sorted array of all suffixes of a given string. 
Let the given string be “banana”. 

0 banana                          5 a
1 anana Sort the Suffixes 3 ana
2 nana ----------------> 1 anana
3 ana alphabetically 0 banana
4 na 4 na
5 a 2 nana

The suffix array for “banana” :
suffix[] = {5, 3, 1, 0, 4, 2}
We have discussed Suffix Array and it O(nLogn) construction .
Once Suffix array is built, we can use it to efficiently search a pattern in a text. For example, we can use Binary Search to find a pattern (Complete code for the same is discussed here)

LCP Array 
The Binary Search based solution discussed here takes O(m*Logn) time where m is length of the pattern to be searched and n is length of the text. With the help of LCP array, we can search a pattern in O(m + Log n) time. For example, if our task is to search “ana” in “banana”, m = 3, n = 5.
LCP Array is an array of size n (like Suffix Array). A value lcp[i] indicates length of the longest common prefix of the suffixes indexed by suffix[i] and suffix[i+1]. suffix[n-1] is not defined as there is no suffix after it. 

txt[0..n-1] = "banana"
suffix[] = {5, 3, 1, 0, 4, 2|
lcp[] = {1, 3, 0, 0, 2, 0}
Suffixes represented by suffix array in order are:
{"a", "ana", "anana", "banana", "na", "nana"}
lcp[0] = Longest Common Prefix of "a" and "ana" = 1
lcp[1] = Longest Common Prefix of "ana" and "anana" = 3
lcp[2] = Longest Common Prefix of "anana" and "banana" = 0
lcp[3] = Longest Common Prefix of "banana" and "na" = 0
lcp[4] = Longest Common Prefix of "na" and "nana" = 2
lcp[5] = Longest Common Prefix of "nana" and None = 0

How to construct LCP array? 
LCP array construction is done two ways: 
1) Compute the LCP array as a byproduct to the suffix array (Manber & Myers Algorithm) 
2) Use an already constructed suffix array in order to compute the LCP values. (Kasai Algorithm).
There exist algorithms that can construct Suffix Array in O(n) time and therefore we can always construct LCP array in O(n) time. But in the below implementation, a O(n Log n) algorithm is discussed.

kasai’s Algorithm 
In this article, kasai’s Algorithm is discussed. The algorithm constructs LCP array from suffix array and input text in O(n) time. The idea is based on below fact:
Let lcp of suffix beginning at txt[i[ be k. If k is greater than 0, then lcp for suffix beginning at txt[i+1] will be at-least k-1. The reason is, relative order of characters remain same. If we delete the first character from both suffixes, we know that at least k characters will match. For example for substring “ana”, lcp is 3, so for string “na” lcp will be at-least 2. Refer this for proof.

Below is the C++ implementation of Kasai’s algorithm. 

C++




// C++ program for building LCP array for given text
#include <bits/stdc++.h>
using namespace std;
 
// Structure to store information of a suffix
struct suffix
{
    int index;  // To store original index
    int rank[2]; // To store ranks and next rank pair
};
 
// A comparison function used by sort() to compare two suffixes
// Compares two pairs, returns 1 if first pair is smaller
int cmp(struct suffix a, struct suffix b)
{
    return (a.rank[0] == b.rank[0])? (a.rank[1] < b.rank[1] ?1: 0):
           (a.rank[0] < b.rank[0] ?1: 0);
}
 
// This is the main function that takes a string 'txt' of size n as an
// argument, builds and return the suffix array for the given string
vector<int> buildSuffixArray(string txt, int n)
{
    // A structure to store suffixes and their indexes
    struct suffix suffixes[n];
 
    // Store suffixes and their indexes in an array of structures.
    // The structure is needed to sort the suffixes alphabetically
    // and maintain their old indexes while sorting
    for (int i = 0; i < n; i++)
    {
        suffixes[i].index = i;
        suffixes[i].rank[0] = txt[i] - 'a';
        suffixes[i].rank[1] = ((i+1) < n)? (txt[i + 1] - 'a'): -1;
    }
 
    // Sort the suffixes using the comparison function
    // defined above.
    sort(suffixes, suffixes+n, cmp);
 
    // At his point, all suffixes are sorted according to first
    // 2 characters.  Let us sort suffixes according to first 4
    // characters, then first 8 and so on
    int ind[n];  // This array is needed to get the index in suffixes[]
    // from original index.  This mapping is needed to get
    // next suffix.
    for (int k = 4; k < 2*n; k = k*2)
    {
        // Assigning rank and index values to first suffix
        int rank = 0;
        int prev_rank = suffixes[0].rank[0];
        suffixes[0].rank[0] = rank;
        ind[suffixes[0].index] = 0;
 
        // Assigning rank to suffixes
        for (int i = 1; i < n; i++)
        {
            // If first rank and next ranks are same as that of previous
            // suffix in array, assign the same new rank to this suffix
            if (suffixes[i].rank[0] == prev_rank &&
                    suffixes[i].rank[1] == suffixes[i-1].rank[1])
            {
                prev_rank = suffixes[i].rank[0];
                suffixes[i].rank[0] = rank;
            }
            else // Otherwise increment rank and assign
            {
                prev_rank = suffixes[i].rank[0];
                suffixes[i].rank[0] = ++rank;
            }
            ind[suffixes[i].index] = i;
        }
 
        // Assign next rank to every suffix
        for (int i = 0; i < n; i++)
        {
            int nextindex = suffixes[i].index + k/2;
            suffixes[i].rank[1] = (nextindex < n)?
                                  suffixes[ind[nextindex]].rank[0]: -1;
        }
 
        // Sort the suffixes according to first k characters
        sort(suffixes, suffixes+n, cmp);
    }
 
    // Store indexes of all sorted suffixes in the suffix array
    vector<int>suffixArr;
    for (int i = 0; i < n; i++)
        suffixArr.push_back(suffixes[i].index);
 
    // Return the suffix array
    return  suffixArr;
}
 
/* To construct and return LCP */
vector<int> kasai(string txt, vector<int> suffixArr)
{
    int n = suffixArr.size();
 
    // To store LCP array
    vector<int> lcp(n, 0);
 
    // An auxiliary array to store inverse of suffix array
    // elements. For example if suffixArr[0] is 5, the
    // invSuff[5] would store 0.  This is used to get next
    // suffix string from suffix array.
    vector<int> invSuff(n, 0);
 
    // Fill values in invSuff[]
    for (int i=0; i < n; i++)
        invSuff[suffixArr[i]] = i;
 
    // Initialize length of previous LCP
    int k = 0;
 
    // Process all suffixes one by one starting from
    // first suffix in txt[]
    for (int i=0; i<n; i++)
    {
        /* If the current suffix is at n-1, then we don’t
           have next substring to consider. So lcp is not
           defined for this substring, we put zero. */
        if (invSuff[i] == n-1)
        {
            k = 0;
            continue;
        }
 
        /* j contains index of the next substring to
           be considered  to compare with the present
           substring, i.e., next string in suffix array */
        int j = suffixArr[invSuff[i]+1];
 
        // Directly start matching from k'th index as
        // at-least k-1 characters will match
        while (i+k<n && j+k<n && txt[i+k]==txt[j+k])
            k++;
 
        lcp[invSuff[i]] = k; // lcp for the present suffix.
 
        // Deleting the starting character from the string.
        if (k>0)
            k--;
    }
 
    // return the constructed lcp array
    return lcp;
}
 
// Utility function to print an array
void printArr(vector<int>arr, int n)
{
    for (int i = 0; i < n; i++)
        cout << arr[i] << " ";
    cout << endl;
}
 
// Driver program
int main()
{
    string str = "banana";
 
    vector<int>suffixArr = buildSuffixArray(str, str.length());
    int n = suffixArr.size();
 
    cout << "Suffix Array : \n";
    printArr(suffixArr, n);
 
    vector<int>lcp = kasai(str, suffixArr);
 
    cout << "\nLCP Array : \n";
    printArr(lcp, n);
    return 0;
}


Java




import java.util.Arrays;
import java.util.Vector;
 
// Structure to store information of a suffix
class Suffix {
    int index;  // To store original index
    int[] rank = new int[2]; // To store ranks and next rank pair
}
 
public class SuffixArray {
 
    // A comparison function used by Arrays.sort() to compare two suffixes
    // Compares two pairs, returns 1 if the first pair is smaller
    static int cmp(Suffix a, Suffix b) {
        return (a.rank[0] == b.rank[0]) ? Integer.compare(a.rank[1], b.rank[1]) : Integer.compare(a.rank[0], b.rank[0]);
    }
 
    // This is the main function that takes a string 'txt' of size n as an
    // argument, builds and returns the suffix array for the given string
    static Vector<Integer> buildSuffixArray(String txt, int n) {
        // A structure to store suffixes and their indexes
        Suffix[] suffixes = new Suffix[n];
 
        // Store suffixes and their indexes in an array of structures.
        // The structure is needed to sort the suffixes alphabetically
        // and maintain their old indexes while sorting
        for (int i = 0; i < n; i++) {
            suffixes[i] = new Suffix();
            suffixes[i].index = i;
            suffixes[i].rank[0] = txt.charAt(i) - 'a';
            suffixes[i].rank[1] = (i + 1) < n ? (txt.charAt(i + 1) - 'a') : -1;
        }
 
        // Sort the suffixes using the comparison function
        // defined above.
        Arrays.sort(suffixes, SuffixArray::cmp);
 
        // At this point, all suffixes are sorted according to the first
        // 2 characters. Let us sort suffixes according to first 4
        // characters, then first 8 and so on
        int[] ind = new int[n];  // This array is needed to get the index in suffixes[]
        // from the original index. This mapping is needed to get
        // the next suffix.
        for (int k = 4; k < 2 * n; k = k * 2) {
            // Assigning rank and index values to the first suffix
            int rank = 0;
            int prev_rank = suffixes[0].rank[0];
            suffixes[0].rank[0] = rank;
            ind[suffixes[0].index] = 0;
 
            // Assigning rank to suffixes
            for (int i = 1; i < n; i++) {
                // If the first rank and next ranks are the same as that of the previous
                // suffix in the array, assign the same new rank to this suffix
                if (suffixes[i].rank[0] == prev_rank &&
                        suffixes[i].rank[1] == suffixes[i - 1].rank[1]) {
                    prev_rank = suffixes[i].rank[0];
                    suffixes[i].rank[0] = rank;
                } else { // Otherwise increment rank and assign
                    prev_rank = suffixes[i].rank[0];
                    suffixes[i].rank[0] = ++rank;
                }
                ind[suffixes[i].index] = i;
            }
 
            // Assign next rank to every suffix
            for (int i = 0; i < n; i++) {
                int nextindex = suffixes[i].index + k / 2;
                suffixes[i].rank[1] = (nextindex < n) ?
                        suffixes[ind[nextindex]].rank[0] : -1;
            }
 
            // Sort the suffixes according to the first k characters
            Arrays.sort(suffixes, SuffixArray::cmp);
        }
 
        // Store indexes of all sorted suffixes in the suffix array
        Vector<Integer> suffixArr = new Vector<>();
        for (int i = 0; i < n; i++)
            suffixArr.add(suffixes[i].index);
 
        // Return the suffix array
        return suffixArr;
    }
 
/* To construct and return LCP */
    static Vector<Integer> kasai(String txt, Vector<Integer> suffixArr) {
        int n = suffixArr.size();
 
        // To store LCP array
          int temp[]=new int[n];
        Vector<Integer> lcp = new Vector<>(n);
 
        // An auxiliary array to store the inverse of the suffix array
        // elements. For example, if suffixArr[0] is 5, the
        // invSuff[5] would store 0. This is used to get the next
        // suffix string from the suffix array.
        int[] invSuff = new int[n];
 
        // Fill values in invSuff[]
        for (int i = 0; i < n; i++)
            invSuff[suffixArr.get(i)] = i;
 
        // Initialize the length of the previous LCP
        int k = 0;
 
        // Process all suffixes one by one starting from
        // the first suffix in txt[]
        for (int i = 0; i < n; i++) {
            /* If the current suffix is at n-1, then we don’t
               have the next substring to consider. So lcp is not
               defined for this substring, we put zero. */
            if (invSuff[i] == n - 1) {
                k = 0;
                continue;
            }
 
            /* j contains the index of the next substring to
               be considered to compare with the present
               substring, i.e., the next string in the suffix array */
            int j = suffixArr.get(invSuff[i] + 1);
 
            // Directly start matching from k'th index as
            // at least k-1 characters will match
            while (i + k < n && j + k < n && txt.charAt(i + k) == txt.charAt(j + k))
                k++;
 
              temp[invSuff[i]]=k;// lcp for the present suffix.
 
            // Deleting the starting character from the string.
            if (k > 0)
                k--;
        }
 
          for(int i=0;i<n;i++) {
          lcp.add(temp[i]);
        }
        // return the constructed lcp array
        return lcp;
    }         
 
    // Utility function to print an array
static void printArr(Vector<Integer> arr,int n) {
    for (Integer value : arr)
        System.out.print(value + " ");
    System.out.println();
}
 
    // Driver program
    public static void main(String[] args) {
        String str = "banana";
 
        Vector<Integer> suffixArr = buildSuffixArray(str, str.length());
        int n = suffixArr.size();
 
        System.out.println("Suffix Array : ");
        printArr(suffixArr, n);
 
        Vector<Integer> lcp = kasai(str, suffixArr);
 
        System.out.println("\nLCP Array : ");
        printArr(lcp, n);
    }
}


Python




class Suffix:
    def __init__(self):
        self.index = 0
        self.rank = [0, 0]
 
def buildSuffixArray(txt, n):
    suffixes = [Suffix() for _ in range(n)]
 
    for i in range(n):
        suffixes[i].index = i
        suffixes[i].rank[0] = ord(txt[i]) - ord('a')
        suffixes[i].rank[1] = ord(txt[i + 1]) - ord('a') if i + 1 < n else -1
 
    suffixes.sort(key=lambda x: (x.rank[0], x.rank[1]))
 
    ind = [0] * n
    for k in range(4, 2 * n, k * 2) if 'k' in locals() and k > 0 else range(4, 2 * n, 1):
        rank = 0
        prev_rank = suffixes[0].rank[0]
        suffixes[0].rank[0] = rank
        ind[suffixes[0].index] = 0
 
        for i in range(1, n):
            if suffixes[i].rank[0] == prev_rank and suffixes[i].rank[1] == suffixes[i - 1].rank[1]:
                prev_rank = suffixes[i].rank[0]
                suffixes[i].rank[0] = rank
            else:
                prev_rank = suffixes[i].rank[0]
                suffixes[i].rank[0] = rank + 1
            ind[suffixes[i].index] = i
 
        for i in range(n):
            nextindex = suffixes[i].index + k // 2
            suffixes[i].rank[1] = suffixes[ind[nextindex]].rank[0] if nextindex < n else -1
 
        suffixes.sort(key=lambda x: (x.rank[0], x.rank[1]))
 
    suffixArr = [suffix.index for suffix in suffixes]
    return suffixArr
 
def kasai(txt, suffixArr):
    n = len(suffixArr)
    lcp = [0] * n
    invSuff = [0] * n
 
    for i in range(n):
        invSuff[suffixArr[i]] = i
 
    k = 0
 
    for i in range(n):
        if invSuff[i] == n - 1:
            k = 0
            continue
 
        j = suffixArr[invSuff[i] + 1]
 
        while i + k < n and j + k < n and txt[i + k] == txt[j + k]:
            k += 1
 
        lcp[invSuff[i]] = k
 
        if k > 0:
            k -= 1
 
    return lcp
 
# Utility function to print an array
def printArr(arr):
    print(" ".join(map(str, arr)))
 
# Driver program
if __name__ == "__main__":
    input_str = "banana"
 
    suffixArr = buildSuffixArray(input_str, len(input_str))
    n = len(suffixArr)
 
    print("Suffix Array:")
    printArr(suffixArr)
 
    lcp = kasai(input_str, suffixArr)
 
    print("\nLCP Array:")
    printArr(lcp)


C#




using System;
using System.Collections.Generic;
 
// Structure to store information of a suffix
public struct Suffix
{
    public int Index; // To store original index
    public int[] Rank; // To store ranks and next rank pair
}
 
public class SuffixArray {
    // A comparison function used by Sort() to compare two
    // suffixes
    // Compares two pairs, returns -1 if the first pair is
    // smaller
    private static int CompareSuffixes(Suffix a, Suffix b)
    {
        return (a.Rank[0] == b.Rank[0])
            ? (a.Rank[1] < b.Rank[1] ? -1 : 1)
            : (a.Rank[0] < b.Rank[0] ? -1 : 1);
    }
 
    // This is the main function that takes a string 'txt'
    // of size n as an argument, builds and returns the
    // suffix array for the given string
    public static List<int> BuildSuffixArray(string txt,
                                             int n)
    {
        // A structure to store suffixes and their indexes
        Suffix[] suffixes = new Suffix[n];
 
        // Store suffixes and their indexes in an array of
        // structures. The structure is needed to sort the
        // suffixes alphabetically and maintain their old
        // indexes while sorting
        for (int i = 0; i < n; i++) {
            suffixes[i].Index = i;
            suffixes[i].Rank = new int[2] {
                txt[i] - 'a',
                (i + 1) < n ? txt[i + 1] - 'a' : -1
            };
        }
 
        // Sort the suffixes using the comparison function
        // defined above.
        Array.Sort(suffixes, CompareSuffixes);
 
        // At this point, all suffixes are sorted according
        // to the first 2 characters. Let us sort suffixes
        // according to the first 4 characters, then first 8
        // and so on
        int[] ind
            = new int[n]; // This array is needed to get the
                          // index in suffixes[] from the
                          // original index. This mapping is
                          // needed to get the next suffix.
        for (int k = 4; k < 2 * n; k = k * 2) {
            // Assigning rank and index values to the first
            // suffix
            int rank = 0;
            int prevRank = suffixes[0].Rank[0];
            suffixes[0].Rank[0] = rank;
            ind[suffixes[0].Index] = 0;
 
            // Assigning rank to suffixes
            for (int i = 1; i < n; i++) {
                // If the first rank and next ranks are the
                // same as that of the previous suffix in
                // the array, assign the same new rank to
                // this suffix
                if (suffixes[i].Rank[0] == prevRank
                    && suffixes[i].Rank[1]
                           == suffixes[i - 1].Rank[1]) {
                    prevRank = suffixes[i].Rank[0];
                    suffixes[i].Rank[0] = rank;
                }
                else // Otherwise increment rank and assign
                {
                    prevRank = suffixes[i].Rank[0];
                    suffixes[i].Rank[0] = ++rank;
                }
                ind[suffixes[i].Index] = i;
            }
 
            // Assign the next rank to every suffix
            for (int i = 0; i < n; i++) {
                int nextIndex = suffixes[i].Index + k / 2;
                suffixes[i].Rank[1]
                    = (nextIndex < n)
                          ? suffixes[ind[nextIndex]].Rank[0]
                          : -1;
            }
 
            // Sort the suffixes according to the first k
            // characters
            Array.Sort(suffixes, CompareSuffixes);
        }
 
        // Store indexes of all sorted suffixes in the
        // suffix array
        List<int> suffixArr = new List<int>();
        for (int i = 0; i < n; i++)
            suffixArr.Add(suffixes[i].Index);
 
        // Return the suffix array
        return suffixArr;
    }
 
    /* To construct and return LCP */
    public static List<int> Kasai(string txt,
                                  List<int> suffixArr)
    {
        int n = suffixArr.Count;
 
        // To store the LCP array
        List<int> lcp = new List<int>(new int[n]);
 
        // An auxiliary array to store the inverse of suffix
        // array elements. For example, if suffixArr[0] is
        // 5, the invSuff[5] would store 0.  This is used to
        // get the next suffix string from the suffix array.
        int[] invSuff = new int[n];
 
        // Fill values in invSuff[]
        for (int i = 0; i < n; i++)
            invSuff[suffixArr[i]] = i;
 
        // Initialize the length of the previous LCP
        int k = 0;
 
        // Process all suffixes one by one starting from
        // the first suffix in txt[]
        for (int i = 0; i < n; i++) {
            /* If the current suffix is at n-1, then we
               don’t have the next substring to consider. So
               LCP is not
               defined for this substring, we put zero. */
            if (invSuff[i] == n - 1) {
                k = 0;
                continue;
            }
 
            /* j contains the index of the next substring to
               be considered to compare with the present
               substring, i.e., the next string in the
               suffix array */
            int j = suffixArr[invSuff[i] + 1];
 
            // Directly start matching from the k'th index
            // as at least k-1 characters will match
            while (i + k < n && j + k < n
                   && txt[i + k] == txt[j + k])
                k++;
 
            lcp[invSuff[i]]
                = k; // LCP for the present suffix.
 
            // Deleting the starting character from the
            // string.
            if (k > 0)
                k--;
        }
 
        // Return the constructed LCP array
        return lcp;
    }
 
    // Utility function to print an array
    public static void PrintArr(List<int> arr, int n)
    {
        for (int i = 0; i < n; i++)
            Console.Write(arr[i] + " ");
        Console.WriteLine();
    }
 
    // Driver program
    public static void Main()
    {
        string str = "banana";
 
        List<int> suffixArr
            = BuildSuffixArray(str, str.Length);
        int n = suffixArr.Count;
 
        Console.WriteLine("Suffix Array :");
        PrintArr(suffixArr, n);
 
        List<int> lcp = Kasai(str, suffixArr);
 
        Console.WriteLine("\nLCP Array :");
        PrintArr(lcp, n);
    }
}
 
// This code is contributed by shivamgupta0987654321


Javascript




// Define a class for storing suffix information
class Suffix {
    constructor(index, rank1, rank2) {
        this.index = index; // Store the original index
        this.rank = [rank1, rank2]; // Store ranks and next rank pair
    }
}
 
// Comparison function used for sorting suffixes
function cmp(a, b) {
    // Compare ranks of suffixes
    return (a.rank[0] === b.rank[0]) ? (a.rank[1] < b.rank[1] ? -1 : 1) :
        (a.rank[0] < b.rank[0] ? -1 : 1);
}
 
// Function to build the suffix array of a given text
function buildSuffixArray(txt) {
    const n = txt.length;
    const suffixes = [];
 
    // Generate suffixes and their ranks
    for (let i = 0; i < n; i++) {
        suffixes[i] = new Suffix(i, txt.charCodeAt(i) - 'a'.charCodeAt(0),
            ((i + 1) < n) ? txt.charCodeAt(i + 1) - 'a'.charCodeAt(0) : -1);
    }
 
    // Sort the generated suffixes using the comparison function
    suffixes.sort(cmp);
 
    // Array to map the original index of suffixes after sorting
    const ind = new Array(n).fill(0);
 
    // Loop for sorting suffixes based on multiple characters
    for (let k = 4; k < 2 * n; k *= 2) {
        let rank = 0;
        let prevRank = suffixes[0].rank[0];
        suffixes[0].rank[0] = rank;
        ind[suffixes[0].index] = 0;
 
        for (let i = 1; i < n; i++) {
            if (suffixes[i].rank[0] === prevRank &&
                suffixes[i].rank[1] === suffixes[i - 1].rank[1]) {
                prevRank = suffixes[i].rank[0];
                suffixes[i].rank[0] = rank;
            } else {
                prevRank = suffixes[i].rank[0];
                suffixes[i].rank[0] = ++rank;
            }
            ind[suffixes[i].index] = i;
        }
 
        for (let i = 0; i < n; i++) {
            const nextIndex = suffixes[i].index + k / 2;
            suffixes[i].rank[1] = (nextIndex < n) ?
                suffixes[ind[nextIndex]].rank[0] : -1;
        }
 
        suffixes.sort(cmp);
    }
 
    // Create the suffix array from the sorted suffixes
    const suffixArr = suffixes.map(suffix => suffix.index);
 
    return suffixArr; // Return the suffix array
}
 
// Function to construct and return the LCP (Longest Common Prefix) array
function kasai(txt, suffixArr) {
    const n = suffixArr.length;
    const lcp = new Array(n).fill(0);
    const invSuff = new Array(n).fill(0);
 
    // Fill the inverse suffix array
    for (let i = 0; i < n; i++)
        invSuff[suffixArr[i]] = i;
 
    let k = 0;
 
    for (let i = 0; i < n; i++) {
        if (invSuff[i] === n - 1) {
            k = 0;
            continue;
        }
 
        let j = suffixArr[invSuff[i] + 1];
 
        // Compute LCP values using suffix array
        while (i + k < n && j + k < n && txt[i + k] === txt[j + k])
            k++;
 
        lcp[invSuff[i]] = k; // Store the computed LCP
 
        if (k > 0)
            k--;
    }
 
    return lcp; // Return the constructed LCP array
}
 
// Utility function to print an array
function printArr(arr) {
    console.log(arr.join(" ")); // Print array elements separated by spaces
}
 
const str = "banana"; // Input string
 
// Build the suffix array for the input string
const suffixArr = buildSuffixArray(str);
const n = suffixArr.length;
 
console.log("Suffix Array:");
printArr(suffixArr); // Print the generated suffix array
 
// Compute the LCP array using the suffix array
const lcp = kasai(str, suffixArr);
 
console.log("\nLCP Array:");
printArr(lcp); // Print the computed LCP array


Output: 

Suffix Array : 
5 3 1 0 4 2
LCP Array :
1 3 0 0 2 0

Illustration: 

txt[]     = "banana",  suffix[]  = {5, 3, 1, 0, 4, 2| 
Suffix array represents
{"a", "ana", "anana", "banana", "na", "nana"}
Inverse Suffix Array would be
invSuff[] = {3, 2, 5, 1, 4, 0}

LCP values are evaluated in below order
We first compute LCP of first suffix in text which is “banana“. We need next suffix in suffix array to compute LCP (Remember lcp[i] is defined as Longest Common Prefix of suffix[i] and suffix[i+1]). To find the next suffix in suffixArr[], we use SuffInv[]. The next suffix is “na”. Since there is no common prefix between “banana” and “na”, the value of LCP for “banana” is 0 and it is at index 3 in suffix array, so we fill lcp[3] as 0.
Next we compute LCP of second suffix which “anana“. Next suffix of “anana” in suffix array is “banana”. Since there is no common prefix, the value of LCP for “anana” is 0 and it is at index 2 in suffix array, so we fill lcp[2] as 0.
Next we compute LCP of third suffix which “nana“. Since there is no next suffix, the value of LCP for “nana” is not defined. We fill lcp[5] as 0.
Next suffix in text is “ana”. Next suffix of “ana” in suffix array is “anana”. Since there is a common prefix of length 3, the value of LCP for “ana” is 3. We fill lcp[1] as 3.
Now we lcp for next suffix in text which is “na“. This is where Kasai’s algorithm uses the trick that LCP value must be at least 2 because previous LCP value was 3. Since there is no character after “na”, final value of LCP is 2. We fill lcp[4] as 2.
Next suffix in text is “a“. LCP value must be at least 1 because the previous value was 2. Since there is no character after “a”, final value of LCP is 1. We fill lcp[0] as 1.
We will soon be discussing the implementation of search with the help of LCP array and how LCP array helps in reducing time complexity to O(m + Log n).

References: 
http://web.stanford.edu/class/cs97si/suffix-array.pdf 
http://www.mi.fu-berlin.de/wiki/pub/ABI/RnaSeqP4/suffix-array.pdf 
http://codeforces.com/blog/entry/12796


 



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads