Print Kth character in sorted concatenated substrings of a string | Structure to store information of a suffix ; To store original index ; To store ranks and next rank pair ; 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 ; A structure to store suffixes and their indexes ; Store suffixes and their indexes in an array of structures . The structure is needed to sort the suffixes alphabatically and maintain their old indexes while sorting ; Sort the suffixes using the comparison function defined above . ; 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 ; This array is needed to get the index in suffixes [ ] from original index . This mapping is needed to get next suffix . ; Assigning rank and index values to first suffix ; Assigning rank to suffixes ; If first rank and next ranks are same as that of previous suffix in array , assign the same new rank to this suffix ; Otherwise increment rank and assign ; Assign next rank to every suffix ; Sort the suffixes according to first k characters ; Store indexes of all sorted suffixes in the suffix array ; Return the suffix array ; To construct and return LCP ; To store LCP array ; 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 . ; Fill values in invSuff [ ] ; Initialize length of previous LCP ; Process all suffixes one by one starting from first suffix in txt [ ] ; If the current suffix is at n - 1 , then we dont have next substring to consider . So lcp is not defined for this substring , we put zero . ; j contains index of the next substring to be considered to compare with the present substring , i . e . , next string in suffix array ; Directly start matching from k 'th index as  at-least k-1 characters will match ; Deleting the starting character from the string . ; Return the constructed lcp array ; Utility method to get sum of first N numbers ; Returns Kth character in sorted concatenated substrings of str ; Calculating suffix array and lcp array ; Skipping characters common to substring ( n - suffixArr [ i ] ) is length of current maximum substring lcp [ i ] will length of common substring ; If characters are more than K , that means Kth character belongs to substring corresponding to current lcp [ i ] ; Loop from current lcp value to current string length ; Again reduce K by current substring 's  length one by one and when it becomes less,  print Kth character of current substring ; Driver code
class suffix : NEW_LINE INDENT def __init__ ( self ) : NEW_LINE INDENT self . index = 0 NEW_LINE self . rank = [ 0 ] * 2 NEW_LINE DEDENT DEDENT def buildSuffixArray ( txt : str , n : int ) -> list : NEW_LINE INDENT suffixes = [ 0 ] * n NEW_LINE for i in range ( n ) : NEW_LINE INDENT suffixes [ i ] = suffix ( ) NEW_LINE DEDENT for i in range ( n ) : NEW_LINE INDENT suffixes [ i ] . index = i NEW_LINE suffixes [ i ] . rank [ 0 ] = ord ( txt [ i ] ) - ord ( ' a ' ) NEW_LINE suffixes [ i ] . rank [ 1 ] = ( ord ( txt [ i + 1 ] ) - ord ( ' a ' ) ) if ( ( i + 1 ) < n ) else - 1 NEW_LINE DEDENT suffixes . sort ( key = lambda a : a . rank ) NEW_LINE ind = [ 0 ] * n NEW_LINE k = 4 NEW_LINE while k < 2 * n : NEW_LINE INDENT k *= 2 NEW_LINE rank = 0 NEW_LINE prev_rank = suffixes [ 0 ] . rank [ 0 ] NEW_LINE suffixes [ 0 ] . rank [ 0 ] = rank NEW_LINE ind [ suffixes [ 0 ] . index ] = 0 NEW_LINE for i in range ( 1 , n ) : NEW_LINE INDENT if ( suffixes [ i ] . rank [ 0 ] == prev_rank and suffixes [ i ] . rank [ 1 ] == suffixes [ i - 1 ] . rank [ 1 ] ) : NEW_LINE INDENT prev_rank = suffixes [ i ] . rank [ 0 ] NEW_LINE suffixes [ i ] . rank [ 0 ] = rank NEW_LINE DEDENT else : NEW_LINE INDENT prev_rank = suffixes [ i ] . rank [ 0 ] NEW_LINE rank += 1 NEW_LINE suffixes [ i ] . rank [ 0 ] = rank NEW_LINE DEDENT ind [ suffixes [ i ] . index ] = i NEW_LINE DEDENT for i in range ( n ) : NEW_LINE INDENT nextindex = suffixes [ i ] . index + k // 2 NEW_LINE suffixes [ i ] . rank [ 1 ] = suffixes [ ind [ nextindex ] ] . rank [ 0 ] if ( nextindex < n ) else - 1 NEW_LINE DEDENT suffixes . sort ( key = lambda a : a . rank ) NEW_LINE DEDENT suffixArr = [ ] NEW_LINE for i in range ( n ) : NEW_LINE INDENT suffixArr . append ( suffixes [ i ] . index ) NEW_LINE DEDENT return suffixArr NEW_LINE DEDENT def kasai ( txt : str , suffixArr : list ) -> list : NEW_LINE INDENT n = len ( suffixArr ) NEW_LINE lcp = [ 0 ] * n NEW_LINE invSuff = [ 0 ] * n NEW_LINE for i in range ( n ) : NEW_LINE INDENT invSuff [ suffixArr [ i ] ] = i NEW_LINE DEDENT k = 0 NEW_LINE for i in range ( n ) : NEW_LINE INDENT if ( invSuff [ i ] == n - 1 ) : NEW_LINE INDENT k = 0 NEW_LINE continue NEW_LINE DEDENT j = suffixArr [ invSuff [ i ] + 1 ] NEW_LINE while ( i + k < n and j + k < n and txt [ i + k ] == txt [ j + k ] ) : NEW_LINE INDENT k += 1 NEW_LINE DEDENT lcp [ invSuff [ i ] ] = k NEW_LINE if ( k > 0 ) : NEW_LINE INDENT k -= 1 NEW_LINE DEDENT DEDENT return lcp NEW_LINE DEDENT def sumOfFirstN ( N : int ) -> int : NEW_LINE INDENT return ( N * ( N + 1 ) ) // 2 NEW_LINE DEDENT def printKthCharInConcatSubstring ( string : str , K : int ) -> str : NEW_LINE INDENT n = len ( string ) NEW_LINE suffixArr = buildSuffixArray ( string , n ) NEW_LINE lcp = kasai ( string , suffixArr ) NEW_LINE for i in range ( len ( lcp ) ) : NEW_LINE INDENT charToSkip = ( sumOfFirstN ( n - suffixArr [ i ] ) - sumOfFirstN ( lcp [ i ] ) ) NEW_LINE if ( K <= charToSkip ) : NEW_LINE INDENT for j in range ( lcp [ i ] + 1 , ( n - suffixArr [ i ] ) + 1 ) : NEW_LINE INDENT curSubstringLen = j NEW_LINE if ( K <= curSubstringLen ) : NEW_LINE INDENT return string [ ( suffixArr [ i ] + K - 1 ) ] NEW_LINE DEDENT else : NEW_LINE INDENT K -= curSubstringLen NEW_LINE DEDENT DEDENT break NEW_LINE DEDENT else : NEW_LINE INDENT K -= charToSkip NEW_LINE DEDENT DEDENT DEDENT if __name__ == " _ _ main _ _ " : NEW_LINE INDENT string = " banana " NEW_LINE K = 10 NEW_LINE print ( printKthCharInConcatSubstring ( string , K ) ) NEW_LINE DEDENT