Lexicographic rank of a string among all its substrings


String manipulation is an essential topic in computer science that involves operations such as concatenation, substring, reversing, and more. One interesting problem related to string manipulation is to find the lexicographic rank of a string among all its substrings. In this article, we will discuss an algorithm to solve this problem using recursion and backtracking.

Problem Statement

Given a string S of length N, we have to find the lexicographic rank of S among all its substrings. The lexicographic rank is defined as the position of a string in the lexicographically sorted list of all its substrings.

Approach

We can solve this problem using a recursive and backtracking approach. We will generate all possible substrings of the given string S and keep track of the number of substrings that come before S in lexicographic order.

Let's see the algorithm in detail −

  • Initialize a variable "rank" to 1.

  • Generate all possible substrings of the given string S using recursion and backtracking.

  • For each substring, compare it with the given string S and increment the "rank" variable if the substring comes before S in lexicographic order.

  • Return the "rank" variable.

Example

Here're the codes to implement the above algorithm −

#include <stdio.h>
#include <string.h>

// Function to generate all substrings and find their lexicographic rank
void generateSubstrings(const char* s, char* temp, int start, int end, int* rank) {
   if (start > end) {
      if (strcmp(temp, s) < 0) {
         (*rank)++;
      }
      return;
   }
   
   generateSubstrings(s, temp, start + 1, end, rank);
   
   char new_temp[end - start + 2];
   strncpy(new_temp, temp, start);
   new_temp[start] = s[start];
   new_temp[start + 1] = '\0';
   generateSubstrings(s, new_temp, start + 1, end, rank);
}

// Function to find the lexicographic rank of a string
int lexicographicRank(const char* s) {
   int rank = 1;
   generateSubstrings(s, "", 0, strlen(s) - 1, &rank);
   return rank;
}

int main() {
   const char* s = "abc";
   printf("String: %s\n", s);
   printf("Lexicographic Rank: %d\n", lexicographicRank(s));
   return 0;
}

Output

String: abc
Lexicographic Rank: 8
#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

void generateSubstrings(string s, string temp, int start, int end, int& rank) {
   if (start > end) {
      if (temp < s) {
         rank++;
      }
      return;
   }
   
   generateSubstrings(s, temp, start + 1, end, rank);
   generateSubstrings(s, temp + s[start], start + 1, end, rank);
}

int lexicographicRank(string s) {
   int rank = 1;
   generateSubstrings(s, "", 0, s.length() - 1, rank);
   return rank;
}

int main() {
   string s = "abc";
   cout << "String: " << s << endl;
   cout << "Lexicographic Rank: " << lexicographicRank(s) << endl;
   return 0;
}

Output

String: abc
Lexicographic Rank: 4
public class Main {
   // Function to generate all substrings and find their lexicographic rank
   static void generateSubstrings(String s, StringBuilder temp, int start, int end, int[] rank) {
      if (start > end) {
         if (temp.toString().compareTo(s) < 0) {
            rank[0]++;
         }
         return;
      }

      generateSubstrings(s, temp, start + 1, end, rank);

      temp.append(s.charAt(start));
      generateSubstrings(s, temp, start + 1, end, rank);
      temp.setLength(temp.length() - 1); // Remove the last character from temp
   }

   // Function to find the lexicographic rank of a string
   static int lexicographicRank(String s) {
      int[] rank = {1};
      generateSubstrings(s, new StringBuilder(), 0, s.length() - 1, rank);
      return rank[0];
   }

   public static void main(String[] args) {
      String s = "abc";
      System.out.println("String: " + s);
      System.out.println("Lexicographic Rank: " + lexicographicRank(s));
   }
}

Output

String: abc
Lexicographic Rank: 4
def generate_substrings(s, temp, start, end, rank):
   if start > end:
      if temp < s:
         rank[0] += 1
      return

   generate_substrings(s, temp, start + 1, end, rank)
   generate_substrings(s, temp + s[start], start + 1, end, rank)

def lexicographic_rank(s):
   rank = [1]
   generate_substrings(s, "", 0, len(s) - 1, rank)
   return rank[0]

if __name__ == "__main__":
   s = "abc"
   print("String:", s)
   print("Lexicographic Rank:", lexicographic_rank(s))

Output

String: abc
Lexicographic Rank: 4

Explanation of Test Case

Let's take the string "abc" as an example. We need to find the lexicographic rank of all its substrings.

  • Initially, we have an empty string, which has a lexicographic rank of 1.

  • The substring "a" has a lexicographic rank of 1, as it is the first substring in lexicographic order.

  • The substring "ab" has a lexicographic rank of 2, as it comes after "a" in lexicographic order.

  • The substring "abc" has a lexicographic rank of 4, as it comes after "a", "ab", and "ac" in lexicographic order.

  • The substring "b" has a lexicographic rank of 3, as it comes after "a" but before "c" in lexicographic order.

  • The substring "bc" has a lexicographic rank of 5, as it comes after "ab" and "ac" but before "c" in lexicographic order.

  • The substring "c" has a lexicographic rank of 6, as it comes after "a", "ab", "ac", and "b" in lexicographic order.

  • Therefore, the lexicographic rank of all substrings of "abc" is: [1, 1, 2, 3, 4, 5, 6].

Conclusion

In this article, we have discussed an algorithm to find the lexicographic rank of a string among all its substrings using recursion and backtracking. This approach can be used to solve other problems related to string manipulation as well.

Updated on: 23-Oct-2023

442 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements