Lyndon Array Construction during Burrows-Wheeler Inversion

10/27/2017 ∙ by Felipe A. Louza, et al. ∙ Universidade de São Paulo Università del Piemonte Orientale University of Campinas McMaster University 0

In this paper we present an algorithm to compute the Lyndon array of a string T of length n as a byproduct of the inversion of the Burrows-Wheeler transform of T. Our algorithm runs in linear time using only a stack in addition to the data structures used for Burrows-Wheeler inversion. We compare our algorithm with two other linear-time algorithms for Lyndon array construction and show that computing the Burrows-Wheeler transform and then constructing the Lyndon array is competitive compared to the known approaches. We also propose a new balanced parenthesis representation for the Lyndon array that uses 2n+o(n) bits of space and supports constant time access. This representation can be built in linear time using O(n) words of space, or in O(n n/ n) time using asymptotically the same space as T.



There are no comments yet.


page 1

page 2

page 3

page 4

Code Repositories


Computing the Lyndon Array in linear time [JDA 2018, arXiv'19]

view repo
This week in AI

Get the week's most popular data science and artificial intelligence research sent straight to your inbox every Saturday.

1 Introduction

Lyndon words were introduced to find bases of the free Lie algebra CFL58 , and have been extensively applied in algebra and combinatorics. The term “Lyndon array” was apparently introduced in Franek2016 , essentially equivalent to the “Lyndon tree” of Hohlweg & Reutenauer Hohlweg2003 . Interest in Lyndon arrays has been sparked by the surprising characterization of runs through Lyndon words by Bannai et al. Bannai2014 , who were thus able to resolve the long-standing conjecture that the number of runs (maximal periodicities) in any string of length is less than .

The Burrows-Wheeler transform (BWT) Burrows1994 plays a fundamental role in data compression and in text indexing Ohlebusch2013 ; Makinen2015 ; Navarro2016 . Embedded into a wavelet tree, the BWT is a self-index with a remarkable time/space tradeoff Ferragina2000 ; Grossi2003 .

In this article we introduce a linear time algorithm to construct the Lyndon array of a string of length , from an ordered alphabet of size , as a byproduct of Burrows-Wheeler inversion, thus establishing an apparently unremarked connection between BWT and Lyndon array construction. We compare our algorithm to others in the literature that also compute the Lyndon array in worst-case linear time. We find that the new algorithm performs well in practice with a small memory footprint.

Inspired by the inner working of our new algorithm, we propose a representation of the Lyndon array consisting of a balanced parenthesis string of length . Such representation leads to a data structure of size bits, supporting the computation of each entry of the Lyndon array in constant time. We also show that such representation is theoretically appealing since it can be computed from in time using words of space, or in time using bits of space.

This article is organized as follows. Section 2 introduces concepts, notation and related work. Section 3 presents our algorithm and Section 4 shows experimental results. Section 5 describes our balanced parenthesis representation of the Lyndon array and two construction algorithms with different time/space tradeoffs. Section 6 summarizes our conclusions.

2 Concepts, notation and related work

Let be a string of length over an ordered alphabet of size . The -th symbol of is denoted by and the substring is denoted by , for . We assume that always ends with a special symbol , that doesn’t appear elsewhere in and precedes every symbol in . A prefix of is a substring of the form and a suffix is a substring of the form , which will be denoted by . We use the symbol for the lexicographic order relation between strings.

The suffix array (Manber1993 ; Gonnet1992 of a string is an array of integers in the range that gives the lexicographic order of all suffixes of , such that . We denote the inverse of as , . The suffix array can be constructed in linear time using additional space Nong2013 .

The next smaller value array () defined for an array of integers stores in the position of the next value in that is smaller than . If there is no value in smaller than then . Formally, . may be constructed in linear time using additional memory for an auxiliary stack Goto2013 .

Lyndon array

A string of length is called a Lyndon word if it is lexicographically strictly smaller than its rotations CFL58 . Alternatively, if is a Lyndon word and is any factorization of into non-empty strings, then . The Lyndon array of a string , denoted or simply when is understood, has length and stores at each position the length of the longest Lyndon word starting at .

Following Hohlweg2003 , Franek et al. Franek2016 have recently shown that the Lyndon array can be easily computed in linear time by applying the computation to the inverse suffix array (), such that , for . Also, in a recent talk surveying Lyndon array construction, Franek and Smyth Smyth2017 quote an unpublished observation by Cristoph Diegelmann Diegelmann2016 that, in its first phase, the linear-time suffix array construction algorithm by Baier Baier2016 computes a permuted version of the Lyndon array. This permuted version, called , stores in the length of the longest Lyndon word starting at position of . Thus, including the BWT-based algorithm proposed here, there are apparently three algorithms that compute the Lyndon array in worst-case time. In addition, in (Bannai2014, , Lemma 23) a linear-time algorithm is suggested that uses lca/rmq techniques to compute the Lyndon tree. The same paper also gives an algorithm for Lyndon tree calculation described as being “in essence” the same as .

Burrows-Wheeler transform

The Burrows-Wheeler transform (BWT) Burrows1994 ; Adjeroh2008 is a reversible transformation that produces a permutation of the original string such that equal symbols of tend to be clustered in . The BWT can be obtained by adding each circular shift of as a row of a conceptual matrix , lexicographically sorting the rows of producing , and concatenating the symbols in the last column of to form . Alternatively, the BWT can be obtained from the suffix array through the application of the relation if or otherwise.

Burrows-Wheeler inversion, the processing of to obtain , is based on the LF-mapping (last-to-first mapping). Let and be the first and the last columns of the conceptual matrix mentioned above. We have such that if is the occurrence of a symbol in , then corresponds to the position of the occurrence of in .

sorted sorted
circular shifts circular shifts suffixes
1 banana$ $banana 7 5 2 2 1 1 a  $
2 anana$b a$banan 6 4 4 6 2 1 n  a$
3 nana$ba ana$ban 4 7 4 7 1 2 n  ana$
4 ana$ban anana$b 2 3 6 5 2 2 b  anana$
5 na$bana banana$ 1 6 6 1 1 1 $  banana$
6 a$banan na$bana 5 2 7 3 1 1 a  na$
7 $banana nana$ba 3 1 8 4 1 1 a  nana$
Figure 1: Circular shifts, sorted circular shifts, , , , , , , and the sorted suffixes of banana$.

The -mapping can be pre-computed in an array of integers in the range . Given an array of integers of length that stores in the number of symbols in strictly smaller than , can be computed in linear time using bits of additional space (Ohlebusch2013, , Alg. 7.2). Alternatively, can be computed on-the-fly in time querying a wavelet tree Grossi2003 constructed for . Given the and the array, the Burrows-Wheeler inversion can be performed in linear time (Ohlebusch2013, , Alg. 7.3).

Figure 1 shows the circular shifts, the sorted circular shifts, the arrays , , , , , , the and the sorted suffixes of banana$. The longest Lyndon words starting at each position and are underlined in the first and last columns of Figure 1.

3 From the BWT to the Lyndon array

Our starting point is the following characterization of the Lyndon array.

Lemma 1

Let be the smallest position in after position such that suffix is lexicographically smaller than suffix ; that is, . Then the length of the longest Lyndon word starting at position is . If then .

For let be defined as above and . If then , , such that and . Since it follows that , hence and is a Lyndon word. In addition, , hence and is not a Lyndon word.

The above lemma is at the basis of the algorithm by Franek et al. Franek2016 computing as . Since is the lexicographic rank of , is precisely the value used in the lemma. In this section, we use the relationship between -mapping and to design alternative algorithms for Lyndon array construction. Since , and it follows that where denotes the map iterated times.

Given the and the mapping our algorithm computes and the Lyndon array from right to left. Briefly, our algorithm finds, during the Burrows-Wheeler inversion, for each position , the first suffix that is smaller than and using Lemma 1 it computes .

Starting with and an index in the BWT, the algorithm decodes the BWT according to , keeping the visited positions whose indexes are smaller than pos in a stack. The visited positions indicate the suffix ordering: a suffix visited at position is lexicographically smaller than all suffixes visited at positions . The stack stores pairs of integers corresponding to each visited position in iteration . The stack is initialized by pushing . The complete pseudo-code appears in Algorithm 1. Note that lines 1, 2, 7, 8, 15 and 16 are exactly the lines from the Burrows-Wheeler inversion presented in (Ohlebusch2013, , Alg. 7.3).

An element in the stack represents the suffix visited in iteration . At iteration the algorithm pops suffixes that are lexicographically larger than the current suffix . Consequently, at the end of the while loop, the top element represents the next suffix (in text order) that is smaller than and is computed at line 1.

Data: and
Result: and
1 for  do
2       while  do
4       end while
6 end for
Algorithm 1 Lyndon array construction during Burrows-Wheeler inversion


Figure 2 shows a running example of our algorithm to compute the Lyndon array for string during its Burrows-Wheeler inversion. Before step is set to (lines 1–6) is decoded at position and the stack is initialized with the end-of-stack marker . The first loop iteration (lines 7–15) decodes a and finds out that the stack is empty. Then , the pair is pushed on the stack and .

At the second iteration n is decoded and the algorithm checks if the suffix at the top of the stack (a$) is larger then the current suffix (na$). The algorithm does not pop the stack because there is no suffix lexicographically larger than the current one. Then . The pair is pushed on the stack.

At the third iteration a is decoded. The top element, representing suffix na$, is popped since it is larger then the current suffix ana$. Then and the pair is pushed. The next iterations proceed in a similar fashion.

Figure 2: Example of our algorithm in the string . Part (a) shows the algorithms steps from right to left. The arrows illustrate the order in which suffixes are visited by the algorithm, following the LF-mapping. Part (b) shows the Stack and the corresponding suffixes at the end of each step of the algorithm.
Lemma 2

Algorithm 1 computes the text and its Lyndon array  in time using words of space.

Since each instruction takes constant time, the running time is proportional to the number of stack operations, which is since each text position is added to the stack exactly once. The space usage is dominated by the arrays , , and by the stack that use words in total.

4 Experiments

In this section we compare our algorithm with the linear time algorithms of Hohlweg and Reutenauer Hohlweg2003 ; Franek2016 (NSV-Lyndon) and Baier Baier2016 (Baier-Lyndon). All algorithms were adapted to compute only the Lyndon array for an input string . In order to compare our solution with the others, we compute the suffix array for the input string , then we obtain and the array, and finally we construct the Lyndon array during Burrows-Wheeler inversion (Algorithm 1). This procedure will be called BWT-Lyndon. We used algorithm SACA-K Nong2013 to construct in time using working space. was computed in the same space as (overwriting the values) both in BWT-Lyndon and in NSV-Lyndon.

We implemented all algorithms in ANSI C. The source code is publicly available at The experiments were executed on a 64-bit Debian GNU/Linux 8 (kernel 3.16.0-4) system with an Intel Xeon Processor E5-2630 v3 20M Cache -GHz,  GB of internal memory and a TB SATA storage. The sources were compiled by GNU GCC version 4.9.2, with the optimizing option -O3 for all algorithms. The time was measured using the clock() function of C standard libraries and the peak memory usage was measured using malloc_count library111

We used string datasets from Pizza & Chili222 as shown in the first three columns of Tables 1 and 2. The datasets einstein-de, kernel, fib41 and cere are highly repetitive texts The dataset english.1gb is the first 1GB of the original english dataset. In our experiments, each integer array of length is stored using bytes, and each string of length is stored using bytes.

Table 1 shows the running time (in seconds), the peak space memory (in bytes per input symbol) and the working space (in GB) of each algorithm.

Running time

The fastest algorithm was Baier-Lyndon, which overall spent about two-thirds of the time required by BWT-Lyndon, though the timings were much closer for larger alphabets. NSV-Lyndon was slightly faster than BWT-Lyndon, requiring about of the time spent by BWT-Lyndon on average.

Peak space

The smallest peak space was obtained by BWT-Lyndon and NSV-Lyndon, which both use slightly more than  bytes. BWT-Lyndon uses bytes to store the string and the integer arrays and , plus the space used by the stack, which occupied about KB in all experiments, except for dataset cere, in which the stack used KB. The strings and are computed and decoded in the same space. NSV-Lyndon also requires bytes to store the string and the integer arrays and , that plus the space of the stack used to compute  Goto2013 , which used exactly the same amount of memory used by the stack of BWT-Lyndon. The array is computed in the same space as . Baier-Lyndon uses bytes to store , and three auxiliary integer arrays of size .

Working space

The working space is the peak space not counting the space used by the input string and the output array ( bytes). The working space of BWT-Lyndon and NSV-Lyndon were by far the smallest in all experiments. Both algorithms use about of the working space used by Baier-Lyndon. For dataset proteins, BWT-Lyndon and NSV-Lyndon use GB less memory than Baier-Lyndon.

running time peak space working space
[secs] [bytes/n] [GB]










sources 230 201 068 055 057 9 9 17 0.79 0.79 02.36
dblp 97 282 104 087 090 9 9 17 1.10 1.10 03.31
dna 16 385 198 160 113 9 9 17 1.50 1.50 04.51
english.1gb 239 1,047 614 504 427 9 9 17 4.09 4.09 12.27
proteins 27 1,129 631 524 477 9 9 17 4.41 4.41 13.23 117 88 036 032 025 9 9 17 0.35 0.35 01.04
kernel 160 246 100 075 073 9 9 17 0.96 0.96 02.88
fib41 2 256 120 093 018 9 9 17 1.00 1.00 02.99
cere 5 440 215 169 114 9 9 17 1.72 1.72 05.16
Table 1: Experiments with Pizza & Chili datasets. The datasets einstein-de, kernel, fib41 and cere are highly repetitive texts. The running time is shown in seconds. The peak space is given in bytes per input symbol. The working space is given in GB.

Steps (running time)

Table 2 shows the running time (in seconds) for each step of algorithms BWT-Lyndon and NSV-Lyndon. Step 1, constructing , is the most time-consuming part of both algorithms, taking about of the total time. Incidentally, this means that if the input consists of the BWT rather than , our algorithm would clearly be the fastest. In Step 2, computing is faster than computing since is more cache-efficient than . Similarly in Step 3, computing is more efficient than computing  Goto2013 . However, Step 4 of BWT-Lyndon, which computes during the Burrows-Wheeler inversion, is sufficiently slower (by a factor of ) than computing from and , so that the overall time of BWT-Lyndon is larger than NSV-Lyndon, as shown in Table 1.

  Step 1 Step 2 Step 3 Step 4







sources 230 201 050.27 02.28 03.49 0.97 01.65 014.12 0.13
dblp 97 282 079.83 04.02 05.51 1.46 01.61 018.80 0.18
dna 16 385 145.02 08.07 09.99 1.48 04.04 043.39 0.25
english.1gb 239 1,047 459.29 21.86 34.35 4.70 10.31 127.65 0.72
proteins 27 1,129 478.13 21.96 34.99 4.71 10.47 125.73 0.75
einstein-de 117 88 028.79 01.27 01.91 0.48 00.85 05.10 0.06
kernel 160 246 068.19 03.52 04.92 1.29 02.18 27.21 0.18
fib41 2 256 085.94 05.94 06.55 1.38 00.60 26.48 0.18
cere 5 440 153.89 09.30 11.20 2.24 04.38 49.38 0.42
Table 2: Experiments with Pizza & Chili datasets. The running time is reported in seconds for each step of algorithms BWT-Lyndon and NSV-Lyndon.

5 Balanced parenthesis representation of a Lyndon Array

In this section we introduce a new representation for the Lyndon array of consisting of a balanced parenthesis string of length . The existence of this representation is not surprising in view of Observation 3 in Franek2016 stating that Lyndon words do not overlap (see also the bracketing algorithm in SawadaR03 ). Algorithm 2 gives an operational strategy for building such a representation, and the next lemma shows how to use it to retrieve individual values of . In the following, given a balanced parenthesis string , we write (resp. ) to denote the position in of the -th open parenthesis (resp. the position in of the closed parenthesis closing the -th open parenthesis).

1 for  do
2       while  do
4       end while
6 end for
Algorithm 2 Balanced parenthesis representation from
Lemma 3

The balanced parenthesis array computed by Algorithm 2 is such that setting for




First note that at the -th iteration we append an open parenthesis to and add the value to the stack. The value is removed from the stack as soon as a smaller element is encountered. Since the last value is the smallest element, at the end of the for loop the stack only contains the value 1, which is removed at the exit of the loop. Observing that we append a closed parenthesis to every time a value is removed from the stack, at the end of the algorithm indeed contains open and closed parentheses. Because of the use of the stack, the closing parenthesis follow a first-in last-out logic so the parenthesis are balanced.

By construction, for , the closed parenthesis corresponding to is written immediately before the open parenthesis corresponding to . Hence, between the open and closed parenthesis corresponding to there is a pair of open/closed parenthesis for each entry , . Hence, using the notation (1) and Lemma 1 it is

which implies (2). Finally, for we have and , so and the lemma follows.

Using the range min-max tree from NStalg12 we can represent in bits of space and support , and in time. We have therefore established the following result.

Theorem 1

It is possible to represent the Lyndon array for a text in bits such that we can retrive every value in time.

Since the new representation takes bits, it is desirable to build it without storing explicitly , which takes words. In Section 3 we used the map to generate the  values right-to-left (from to ). Since in Algorithm 2 we need to generate the  values left-to-right, we use the inverse permutation of the map, known in the literature as the map. Formally, for is defined as

Lemma 4

Assume we have a data structure supporting the operation on the BWT in time. Then, we can generate the values in time using additional bits of space.

By (3) it follows that and, for , . To prove the lemma we need to show how to compute each in time. By definition, is the position in of the character prefixing row in the conceptual matrix defining the BWT. Let denote the binary array such that iff row is the first row of the BWT matrix prefixed by some character . Then, the character prefixing row is given by and

The thesis follows observing that using talg/RamanRS07 we can represent in bits supporting constant time queries.

Lemma 5

Using Algorithm 2 we can compute from the BWT in time using words of space.

We represent using one of the many available data structures taking bits and supporting constant time queries (see BCGNNalgor13 and references therein). By Lemma 4 we can generate the values in overall time using auxiliary space. Since every other operations takes constant time, the running time is proportional to the number of stack operations which is since each is inserted only once in the stack.

Note that the space usage of Algorithm 2 is dominated by the stack, which uses words in the worst case. Since at any given time the stack contains an increasing subsequence of , if we can assume that is a random permutation the average stack size is words (see AD99 ).

We now present an alternative representation for the stack that only uses bits in the worst case and supports pop and push operations in time. We represent the stack with a binary array such that iff the value is currently in the stack. Since the values in the stack are always in increasing order, is sufficient to represent the current status of the stack. In Algorithm 2 when a new element is added to the stack we must first delete the elements larger than . This can be accomplished using rank/select operations. If the elements to be deleted are those returned by for . Summing up, the binary array must support the rank/select operations in addition to changing the value of a single bit. To this end we use the dynamic array representation described in spire/HeM10 which takes bits and support the above operations in (optimal) time. We have therefore established, this new time/space tradeoff for Lyndon array construction.

Lemma 6

Using Algorithm 2 we can compute from the BWT in time using bits of space.

Finally, we point out that if the input consists of the text the asymptotic costs do not change, since we can build the BWT from in time and bits of space soda/MunroNN17 .

Theorem 2

Given we can compute in time using words of space, or in time using bits of space.

6 Summary of Results

In this paper we have described a previously unknown connection between the Burrows-Wheeler transform and the Lyndon array, and proposed a corresponding algorithm to construct the latter during Burrows-Wheeler inversion. The algorithm is guaranteed linear-time and simple, resulting in the good practical performance shown by the experiments.

Although not faster than other linear algorithms, our solution was one of the most space-efficient. In addition, if the input is stored in a BWT-based self index, our algorithm would have a clear advantage in both working space and running time, since it is the only one that uses the LF-map rather than the suffix array.

We also introduced a new balanced parenthesis representation for the Lyndon array using bits supporting time access. We have shown how to build this representation in linear time using words of space, and in time using asymptotically the same space as .

Over all the known algorithms surveyed in Smyth2017

, probably the fastest for real world datasets and the most space-efficient is the folklore

MaxLyn algorithm described in Franek2016 , which makes no use of suffix arrays and requires only constant additional space, but which however requires time in the worst-case. We tested MaxLyn on a string consisting of symbols ‘a’. While the linear-time algorithms run in no more than seconds, MaxLyn takes about hours to compute the Lyndon array. Thus, the challenge that remains is to find a fast and “lightweight” worst-case linear-time algorithm for computing the Lyndon array that avoids the expense of suffix array construction.


The authors thank Uwe Baier for kindly providing the source code of algorithm Baier-Lyndon, and Prof. Nalvo Almeida for granting access to the machine used for the experiments.


F.A.L. was supported by the grant 2017/09105-0 from the São Paulo Research Foundation (FAPESP). The work of W.F.S. was supported in part by a grant from the Natural Sciences & Engineering Research Council of Canada (NSERC). G.M. was supported by the PRIN grant 201534HNXC and INdAM-GNCS Project Efficient algorithms for the analysis of Big Data. G.P.T. acknowledges the support of CNPq.


  • (1) K. T. Chen, R. H. Fox, R. C. Lyndon, Free differential calculus IV — the quotient groups of the lower central series, Ann. Math. 68 (1958) 81–95.
  • (2) F. Franek, A. S. M. S. Islam, M. S. Rahman, W. F. Smyth, Algorithms to compute the lyndon array, in: Proc. PSC, 2016, pp. 172–184.
  • (3) C. Hohlweg, C. Reutenauer, Lyndon words, permutations and trees, Theor. Comput. Sci. 307 (1) (2003) 173–178.
  • (4) H. Bannai, T. I, S. Inenaga, Y. Nakashima, M. Takeda, K. Tsuruta, A new characterization of maximal repetitions by lyndon trees, CoRR abs/1406.0263.
  • (5) M. Burrows, D. Wheeler, A block-sorting lossless data compression algorithm, Tech. rep., Digital SRC Research Report (1994).
  • (6) E. Ohlebusch, Bioinformatics Algorithms: Sequence Analysis, Genome Rearrangements, and Phylogenetic Reconstruction, Oldenbusch Verlag, 2013.
  • (7) V. Mäkinen, D. Belazzougui, F. Cunial, A. I. Tomescu, Genome-Scale Algorithm Design, Cambridge University Press, 2015.
  • (8) G. Navarro, Compact Data Structures – A practical approach, Cambridge University Press, 2016.
  • (9) P. Ferragina, G. Manzini, Opportunistic data structures with applications, in: Proc. FOCS, 2000, pp. 390–398.
  • (10) R. Grossi, A. Gupta, J. S. Vitter, High-order entropy-compressed text indexes, in: Proc. SODA, 2003, pp. 841–850.
  • (11) U. Manber, E. W. Myers, Suffix arrays: A new method for on-line string searches, SIAM J. Comput. 22 (5) (1993) 935–948.
  • (12) G. H. Gonnet, R. A. Baeza-Yates, T. Snider, New indices for text: Pat trees and pat arrays, in: Information Retrieval, Prentice-Hall, Inc., 1992, pp. 66–82.
  • (13) G. Nong, Practical linear-time O(1)-workspace suffix sorting for constant alphabets, ACM Trans. Inform. Syst. 31 (3) (2013) 1–15.
  • (14) K. Goto, H. Bannai, Simpler and faster lempel ziv factorization, in: Proc. DCC, 2013, pp. 133–142.
  • (15) F. Franek, W. F. Smyth, Unexpected equivalence: Lyndon array & suffix array, Talk at London Stringology Days & London Algorithmic Workshop (2017).
  • (16) C. Diegelmann, Personal communication (2016).
  • (17) U. Baier, Linear-time suffix sorting - a new approach for suffix array construction, in: Proc. CPM, 2016, pp. 23:1–23:12.
  • (18)

    D. Adjeroh, T. Bell, A. Mukherjee, The burrows-wheeler transform: data compression, suffix arrays, and pattern matching, Springer, Boston, MA, 2008.

  • (19) J. Sawada, F. Ruskey, Generating lyndon brackets.: An addendum to: Fast algorithms to generate necklaces, unlabeled necklaces and irreducible polynomials over GF(2), J. Algorithms 46 (1) (2003) 21–26.
  • (20) G. Navarro, K. Sadakane, Fully-functional static and dynamic succinct trees, ACM Transactions on Algorithms 10 (3) (2014) article 16.
  • (21) R. Raman, V. Raman, S. R. Satti, Succinct indexable dictionaries with applications to encoding k-ary trees, prefix sums and multisets, ACM Trans. Algorithms 3 (4) (2007) 43.
  • (22) J. Barbay, F. Claude, T. Gagie, G. Navarro, Y. Nekrich, Efficient fully-compressed sequence representations, Algorithmica 69 (1) (2014) 232–268.
  • (23) D. Aldous, P. Diaconis, Longest increasing subsequences: from patience sorting to the Baik-Deift-Johansson theorem, Bull. Amer. Math. Soc. 36 (1999) 413–432.
  • (24) M. He, J. I. Munro, Succinct representations of dynamic strings, in: Proc. SPIRE, 2010, pp. 334–346.
  • (25) J. I. Munro, G. Navarro, Y. Nekrich, Space-efficient construction of compressed indexes in deterministic linear time, in: SODA, SIAM, 2017, pp. 408–424.