Lexicographic rank of a String
Given a string str, find its rank among all its permutations when sorted lexicographically.
Note: The characters a string are all unique.
Examples:
Input: str = “acb”
Output: 2
Explanation: If all the permutations of the string are arranged lexicographically they will be “abc”, “acb”, “bac”, “bca”, “cab”, “cba”. From here it can be clearly that the rank of str is 2.Input: str = “string”
Output: 598Input: str[] = “cba”
Output: Rank = 6
Naive Approach: One simple solution is to generate all the permutations in lexicographic order and store the rank of the current string. After generating a permutation, check if the generated permutation is the same as the given string and return the rank of str.
Algorithm
Define a function to calculate the factorial of a given number using recursion. fact(n): if n <= 1: return 1 return n * fact(n - 1) Define a function to calculate the rank of a given string in lexicographic permutation order. findRank(str): Calculate the length of the input string Initialize the rank as 1 Loop through each character of the string Initialize a variable to count the number of characters less than str[i] Loop through the characters after str[i] Update the rank based on the count of characters less than str[i] multiplied by the factorial of the number of remaining characters Return the final rank of the input string Define the main function.
C++
#include <bits/stdc++.h> using namespace std; // Define a function to calculate the factorial of a given number using recursion int fact( int n) { // Base case: if n is 0 or 1, return 1 if (n <= 1) { return 1; } // Recursive case: return n times the factorial of n-1 return n * fact(n - 1); } // Define a function to calculate the rank of a given string in lexicographic permutation order int findRank(string str) { // Calculate the length of the input string int n = str.length(); // Initialize the rank as 1 int rank = 1; // Loop through each character of the string for ( int i = 0; i < n; i++) { // Initialize a variable to count the number of characters less than str[i] int count = 0; // Loop through the characters after str[i] for ( int j = i + 1; j < n; j++) { // If str[i] is greater than str[j], increment the count variable if (str[i] > str[j]) { count++; } } // Update the rank based on the count of characters less than str[i] // multiplied by the factorial of the number of remaining characters rank += count * fact(n - i - 1); } // Return the final rank of the input string return rank; } // Define the main function int main() { // Define a test string string str = "string" ; // Call the findRank function on the test string and print the result cout << findRank(str) << endl; // Return 0 to indicate successful program completion return 0; } |
Python3
# Define a function to calculate the factorial of a given number using recursion def fact(n): # Base case: if n is 0 or 1, return 1 if n < = 1 : return 1 # Recursive case: return n times the factorial of n-1 return n * fact(n - 1 ) # Define a function to calculate the rank of a given string in lexicographic permutation order def findRank(s): # Calculate the length of the input string n = len (s) # Initialize the rank as 1 rank = 1 # Loop through each character of the string for i in range (n): # Initialize a variable to count the number of characters less than s[i] count = 0 # Loop through the characters after s[i] for j in range (i + 1 , n): # If s[i] is greater than s[j], increment the count variable if s[i] > s[j]: count + = 1 # Update the rank based on the count of characters less than s[i] # multiplied by the factorial of the number of remaining characters rank + = count * fact(n - i - 1 ) # Return the final rank of the input string return rank # Define the main function def main(): # Define a test string s = "string" # Call the findRank function on the test string and print the result print (findRank(s)) # Return 0 to indicate successful program completion return 0 # Call the main function main() |
598
Time Complexity: O(N!) where N is the size of the string
Auxiliary Space: O(1)
Lexicographic rank of a String using the concept of permutation:
The problem can be solved using the concept of permutation, based on the following idea:
For characters in each index, find how many lexicographically smaller strings can be formed when all the characters till that index are fixed. This will give the strings smaller than that and we can get the rank.
For a better understanding follow the below illustration.
Illustration:
Let the given string be “STRING”. In the input string, ‘S’ is the first character. There are total 6 characters and 4 of them are smaller than ‘S’. So there can be 4 * 5! smaller strings where first character is smaller than ‘S’, like following
- G X X X X X
- R X X X X X
- I X X X X X
- N X X X X X
Similarly we can use the same process for the other letters. Fix ‘S’ and find the smaller strings starting with ‘S’.
- Repeat the same process for T, rank is 4*5! + 4*4! +. . .
- Now fix T and repeat the same process for R, rank is 4*5! + 4*4! + 3*3! + . . .
- Now fix R and repeat the same process for I, rank is 4*5! + 4*4! + 3*3! + 1*2! + . . .
- Now fix I and repeat the same process for N, rank is 4*5! + 4*4! + 3*3! + 1*2! + 1*1! + . . .
- Now fic N and repeat the same process for G, rank is 4*5! + 4*4! + 3*3! + 1*2! + 1*1! + 0*0!
If this process is continued the rank = 4*5! + 4*4! + 3*3! + 1*2! + 1*1! + 0*0! = 597. The above computations find count of smaller strings. Therefore rank of given string is count of smaller strings plus 1. The final rank = 1 + 597 = 598
Follow the steps mentioned below to implement the idea:
- Iterate the string from i = 0 to length of string:
- Find the number of characters smaller than the current character.
- Calculate the number of lexicographically smaller that can be formed using them as shown above.
- Add that value to the rank.
- At the end, add 1 with rank and return it as the required answer. [the reason is mentioned above]
Below is the implementation of the above approach.
C++
// C++ program to find lexicographic rank // of a string #include <bits/stdc++.h> using namespace std; // A utility function to find // factorial of n int fact( int n) { return (n <= 1) ? 1 : n * fact(n - 1); } // A utility function to count // smaller characters on right of arr[low] int findSmallerInRight(string str, int low, int high) { int countRight = 0, i; for (i = low + 1; i <= high; ++i) if (str[i] < str[low]) ++countRight; return countRight; } // A function to find rank of a string // in all permutations of characters int findRank(string str) { int len = str.size(); int mul = fact(len); int rank = 1; int countRight; int i; for (i = 0; i < len; ++i) { mul /= len - i; // Count number of chars smaller than str[i] // from str[i+1] to str[len-1] countRight = findSmallerInRight(str, i, len - 1); rank += countRight * mul; } return rank; } // Driver code int main() { string str = "string" ; // Function call cout << findRank(str); return 0; } // This code is contributed by Akanksha Rai |
C
// C program to find lexicographic rank // of a string #include <stdio.h> #include <string.h> // A utility function to find factorial of n int fact( int n) { return (n <= 1) ? 1 : n * fact(n - 1); } // A utility function to count smaller characters // on right of arr[low] int findSmallerInRight( char * str, int low, int high) { int countRight = 0, i; for (i = low + 1; i <= high; ++i) if (str[i] < str[low]) ++countRight; return countRight; } // A function to find rank of a string // in all permutations of characters int findRank( char * str) { int len = strlen (str); int mul = fact(len); int rank = 1; int countRight; int i; for (i = 0; i < len; ++i) { mul /= len - i; // Count number of chars smaller than str[i] // from str[i+1] to str[len-1] countRight = findSmallerInRight(str, i, len - 1); rank += countRight * mul; } return rank; } // Driver code int main() { char str[] = "string" ; // Function call printf ( "%d" , findRank(str)); return 0; } |
Java
// Java program to find lexicographic rank // of a string import java.io.*; import java.util.*; class GFG { // A utility function to find factorial of n static int fact( int n) { return (n <= 1 ) ? 1 : n * fact(n - 1 ); } // A utility function to count smaller // characters on right of arr[low] static int findSmallerInRight(String str, int low, int high) { int countRight = 0 , i; for (i = low + 1 ; i <= high; ++i) if (str.charAt(i) < str.charAt(low)) ++countRight; return countRight; } // A function to find rank of a string in // all permutations of characters static int findRank(String str) { int len = str.length(); int mul = fact(len); int rank = 1 ; int countRight; for ( int i = 0 ; i < len; ++i) { mul /= len - i; // Count number of chars smaller // than str[i] from str[i+1] to // str[len-1] countRight = findSmallerInRight(str, i, len - 1 ); rank += countRight * mul; } return rank; } // Driver code public static void main(String[] args) { String str = "string" ; // Function call System.out.println(findRank(str)); } } // This code is contributed by Nikita Tiwari. |
Python3
# Python program to find lexicographic # rank of a string # A utility function to find factorial # of n def fact(n): f = 1 while n > = 1 : f = f * n n = n - 1 return f # A utility function to count smaller # characters on right of arr[low] def findSmallerInRight(st, low, high): countRight = 0 i = low + 1 while i < = high: if st[i] < st[low]: countRight = countRight + 1 i = i + 1 return countRight # A function to find rank of a string # in all permutations of characters def findRank(st): ln = len (st) mul = fact(ln) rank = 1 i = 0 while i < ln: mul = mul / / (ln - i) # count number of chars smaller # than str[i] from str[i + 1] to # str[len-1] countRight = findSmallerInRight(st, i, ln - 1 ) rank = rank + countRight * mul i = i + 1 return rank # Driver code if __name__ = = '__main__' : st = "string" # Function call print (findRank(st)) # This code is contributed by Nikita Tiwari. |
C#
// C# program to find lexicographic rank // of a string using System; class GFG { // A utility function to find factorial of n static int fact( int n) { return (n <= 1) ? 1 : n * fact(n - 1); } // A utility function to count smaller // characters on right of arr[low] static int findSmallerInRight( string str, int low, int high) { int countRight = 0, i; for (i = low + 1; i <= high; ++i) if (str[i] < str[low]) ++countRight; return countRight; } // A function to find rank of a string in // all permutations of characters static int findRank( string str) { int len = str.Length; int mul = fact(len); int rank = 1; int countRight; for ( int i = 0; i < len; ++i) { mul /= len - i; // Count number of chars smaller // than str[i] from str[i+1] to // str[len-1] countRight = findSmallerInRight(str, i, len - 1); rank += countRight * mul; } return rank; } // Driver code public static void Main() { string str = "string" ; // Function call Console.Write(findRank(str)); } } // This code is contributed nitin mittal. |
PHP
<?php // A utility function to find factorial of n function fact( $n ) { return ( $n <= 1) ? 1 : $n * fact( $n - 1); } // A utility function to count smaller // characters on right of arr[low] function findSmallerInRight( $str , $low , $high ) { $countRight = 0; for ( $i = $low + 1; $i <= $high ; ++ $i ) if ( $str [ $i ] < $str [ $low ]) ++ $countRight ; return $countRight ; } // A function to find rank of a string // in all permutations of characters function findRank ( $str ) { $len = strlen ( $str ); $mul = fact( $len ); $rank = 1; for ( $i = 0; $i < $len ; ++ $i ) { $mul /= $len - $i ; // count number of chars smaller than // str[i] from str[i+1] to str[len-1] $countRight = findSmallerInRight( $str , $i , $len - 1); $rank += $countRight * $mul ; } return $rank ; } // Driver Code $str = "string" ; echo findRank( $str ); // This code is contributed by ChitraNayal ?> |
Javascript
<script> // JavaScript program to find lexicographic rank // A utility function to find factorial of n function fact(n) { return (n <= 1) ? 1 : n * fact(n - 1); } // A utility function to count smaller // characters on right of arr[low] function findSmallerInRight(str, low, high) { let countRight = 0; let i; for (i = low + 1; i <= high; ++i) if (str[i] < str[low]) ++countRight; return countRight; } // A function to find rank of a string // in all permutations of characters function findRank(str) { let len = (str).length; let mul = fact(len); let rank = 1; let countRight; let i; for (i = 0; i < len; ++i) { mul /= len - i; // count number of chars smaller than str[i] // from str[i+1] to str[len-1] countRight = findSmallerInRight(str, i, len - 1); rank += countRight * mul; } return rank; } // Driver code let str = "string" ; document.write(findRank(str)); // This code is contributed by rohan07 </script> |
598
Time Complexity: O(N2)
Auxiliary Space: O(1)
Lexicographic rank of a String in linear time:
The idea of the solution is the same as the above approach. The time complexity can be reduced by creating an auxiliary array of size 256.
Create an array to store the number of characters smaller than the ith character in the whole string and update it after each index of the given string during the iteration of the string.
Below is the implementation of the above approach.
C++
// A O(n) solution for finding rank of string #include <bits/stdc++.h> using namespace std; #define MAX_CHAR 256 // A utility function to find factorial of n int fact( int n) { return (n <= 1) ? 1 : n * fact(n - 1); } // Construct a count array where value at every index // contains count of smaller characters in whole string void populateAndIncreaseCount( int * count, string str) { int i; for (i = 0; str[i]; ++i) ++count[str[i]]; for (i = 1; i < MAX_CHAR; ++i) count[i] += count[i - 1]; } // Removes a character ch from count[] array // constructed by populateAndIncreaseCount() void updatecount( int * count, char ch) { int i; for (i = ch; i < MAX_CHAR; ++i) --count[i]; } // A function to find rank of a string in all permutations // of characters int findRank(string str) { int len = str.size(); int mul = fact(len); int rank = 1, i; // All elements of count[] are initialized with 0 int count[MAX_CHAR] = { 0 }; // Populate the count array such that count[i] // contains count of characters which are present // in str and are smaller than i populateAndIncreaseCount(count, str); for (i = 0; i < len; ++i) { mul /= len - i; // Count number of chars smaller than str[i] // from str[i+1] to str[len-1] rank += count[str[i] - 1] * mul; // Reduce count of characters greater than str[i] updatecount(count, str[i]); } return rank; } // Driver code int main() { string str = "string" ; // Function call cout << findRank(str); return 0; } // This is code is contributed by rathbhupendra |
C
// A O(n) solution for finding rank of string #include <stdio.h> #include <string.h> #define MAX_CHAR 256 // A utility function to find factorial of n int fact( int n) { return (n <= 1) ? 1 : n * fact(n - 1); } // Construct a count array where value at every index // contains count of smaller characters in whole string void populateAndIncreaseCount( int * count, char * str) { int i; for (i = 0; str[i]; ++i) ++count[str[i]]; for (i = 1; i < MAX_CHAR; ++i) count[i] += count[i - 1]; } // Removes a character ch from count[] array // constructed by populateAndIncreaseCount() void updatecount( int * count, char ch) { int i; for (i = ch; i < MAX_CHAR; ++i) --count[i]; } // A function to find rank of a string in all permutations // of characters int findRank( char * str) { int len = strlen (str); int mul = fact(len); int rank = 1, i; // All elements of count[] are initialized with 0 int count[MAX_CHAR] = { 0 }; // Populate the count array such that count[i] // contains count of characters which are present // in str and are smaller than i populateAndIncreaseCount(count, str); for (i = 0; i < len; ++i) { mul /= len - i; // Count number of chars smaller than str[i] // from str[i+1] to str[len-1] rank += count[str[i] - 1] * mul; // Reduce count of characters greater than str[i] updatecount(count, str[i]); } return rank; } // Driver code int main() { char str[] = "string" ; // Function call printf ( "%d" , findRank(str)); return 0; } |
Java
// A O(n) solution for finding rank of string class GFG { static int MAX_CHAR = 256 ; // A utility function to find factorial of n static int fact( int n) { return (n <= 1 ) ? 1 : n * fact(n - 1 ); } // Construct a count array where value at every index // contains count of smaller characters in whole string static void populateAndIncreaseCount( int [] count, String str) { int i; for (i = 0 ; i < str.length(); ++i) ++count[str.charAt(i)]; for (i = 1 ; i < MAX_CHAR; ++i) count[i] += count[i - 1 ]; } // Removes a character ch from count[] array // constructed by populateAndIncreaseCount() static void updatecount( int [] count, char ch) { int i; for (i = ch; i < MAX_CHAR; ++i) --count[i]; } // A function to find rank of a string in all // permutations of characters static int findRank(String str) { int len = str.length(); int mul = fact(len); int rank = 1 , i; // All elements of count[] are initialized with 0 int count[] = new int [MAX_CHAR]; // Populate the count array such that count[i] // contains count of characters which are present // in str and are smaller than i populateAndIncreaseCount(count, str); for (i = 0 ; i < len; ++i) { mul /= len - i; // count number of chars smaller than str[i] // from str[i+1] to str[len-1] rank += count[str.charAt(i) - 1 ] * mul; // Reduce count of characters greater than // str[i] updatecount(count, str.charAt(i)); } return rank; } // Driver code public static void main(String args[]) { String str = "string" ; System.out.println(findRank(str)); } } // This code has been contributed by 29AjayKumar |
Python3
# A O(n) solution for finding rank of string MAX_CHAR = 256 # All elements of count[] are initialized with 0 count = [ 0 ] * (MAX_CHAR + 1 ) # A utility function to find factorial of n def fact(n): return 1 if (n < = 1 ) else (n * fact(n - 1 )) # Construct a count array where value at every index # contains count of smaller characters in whole string def populateAndIncreaseCount( str ): for i in range ( len ( str )): count[ ord ( str [i])] + = 1 for i in range ( 1 , MAX_CHAR): count[i] + = count[i - 1 ] # Removes a character ch from count[] array # constructed by populateAndIncreaseCount() def updatecount(ch): for i in range ( ord (ch), MAX_CHAR): count[i] - = 1 # A function to find rank of a string in all permutations # of characters def findRank( str ): len1 = len ( str ) mul = fact(len1) rank = 1 # Populate the count array such that count[i] # contains count of characters which are present # in str and are smaller than i populateAndIncreaseCount( str ) for i in range (len1): mul = mul / / (len1 - i) # count number of chars smaller than str[i] # from str[i+1] to str[len-1] rank + = count[ ord ( str [i]) - 1 ] * mul # Reduce count of characters greater than str[i] updatecount( str [i]) return rank # Driver code if __name__ = = '__main__' : str = "string" print (findRank( str )) # This is code is contributed by chandan_jnu |
C#
// A O(n) solution for finding rank of string using System; class GFG { static int MAX_CHAR = 256; // A utility function to find factorial of n static int fact( int n) { return (n <= 1) ? 1 : n * fact(n - 1); } // Construct a count array where value at every index // contains count of smaller characters in whole string static void populateAndIncreaseCount( int [] count, char [] str) { int i; for (i = 0; i < str.Length; ++i) ++count[str[i]]; for (i = 1; i < MAX_CHAR; ++i) count[i] += count[i - 1]; } // Removes a character ch from count[] array // constructed by populateAndIncreaseCount() static void updatecount( int [] count, char ch) { int i; for (i = ch; i < MAX_CHAR; ++i) --count[i]; } // A function to find rank of a string in all // permutations of characters static int findRank( char [] str) { int len = str.Length; int mul = fact(len); int rank = 1, i; // all elements of count[] are initialized with 0 int [] count = new int [MAX_CHAR]; // Populate the count array such that count[i] // contains count of characters which are present // in str and are smaller than i populateAndIncreaseCount(count, str); for (i = 0; i < len; ++i) { mul /= len - i; // count number of chars smaller than str[i] // from str[i+1] to str[len-1] rank += count[str[i] - 1] * mul; // Reduce count of characters greater than // str[i] updatecount(count, str[i]); } return rank; } // Driver code public static void Main(String[] args) { char [] str = "string" .ToCharArray(); Console.WriteLine(findRank(str)); } } /* This code contributed by PrinciRaj1992 */ |
PHP
<?php // A O(n) solution for finding rank of string $MAX_CHAR =256; // A utility function to find factorial of n function fact( $n ) { return ( $n <= 1) ? 1 : $n * fact( $n - 1); } // Construct a count array where value at every index // contains count of smaller characters in whole string function populateAndIncreaseCount(& $count , $str ) { global $MAX_CHAR ; for ( $i = 0; $i < strlen ( $str ); ++ $i ) ++ $count [ord( $str [ $i ])]; for ( $i = 1; $i < $MAX_CHAR ; ++ $i ) $count [ $i ] += $count [ $i - 1]; } // Removes a character ch from count[] array // constructed by populateAndIncreaseCount() function updatecount(& $count , $ch ) { global $MAX_CHAR ; for ( $i = ord( $ch ); $i < $MAX_CHAR ; ++ $i ) -- $count [ $i ]; } // A function to find rank of a string in all permutations // of characters function findRank( $str ) { global $MAX_CHAR ; $len = strlen ( $str ); $mul = fact( $len ); $rank = 1; // all elements of count[] are initialized with 0 $count = array_fill (0, $MAX_CHAR + 1, 0); // Populate the count array such that count[i] // contains count of characters which are present // in str and are smaller than i populateAndIncreaseCount( $count , $str ); for ( $i = 0; $i < $len ; ++ $i ) { $mul = (int)( $mul /( $len - $i )); // count number of chars smaller than str[i] // from str[i+1] to str[len-1] $rank += $count [ord( $str [ $i ]) - 1] * $mul ; // Reduce count of characters greater than str[i] updatecount( $count , $str [ $i ]); } return $rank ; } // Driver code $str = "string" ; echo findRank( $str ); // This is code is contributed by chandan_jnu ?> |
Javascript
<script> // A O(n) solution for finding rank of string let MAX_CHAR = 256; // A utility function to find factorial of n function fact(n) { return (n <= 1) ? 1 : n * fact(n - 1); } // Construct a count array where value at every index // contains count of smaller characters in whole string function populateAndIncreaseCount(count,str) { let i; for (i = 0; i < str.length; ++i) ++count[str[i].charCodeAt(0)]; for (i = 1; i < MAX_CHAR; ++i) count[i] += count[i - 1]; } // Removes a character ch from count[] array // constructed by populateAndIncreaseCount() function updatecount(count,ch) { let i; for (i = ch.charCodeAt(0); i < MAX_CHAR; ++i) --count[i]; } // A function to find rank of a string in all permutations // of characters function findRank(str) { let len = str.length; let mul = fact(len); let rank = 1, i; // all elements of count[] are initialized with 0 let count = new Array(MAX_CHAR); for (let i = 0; i < count.length; i++) { count[i] = 0; } // Populate the count array such that count[i] // contains count of characters which are present // in str and are smaller than i populateAndIncreaseCount(count, str); for (i = 0; i < len; ++i) { mul = Math.floor(mul/(len - i)); // count number of chars smaller than str[i] // from str[i+1] to str[len-1] rank += count[str[i].charCodeAt(0) - 1] * mul; // Reduce count of characters greater than str[i] updatecount(count, str[i]); } return rank; } // Driver code let str= "string" .split( "" ); document.write(findRank(str)); // This code is contributed by rag2127 </script> |
598
Time Complexity: O(N)
Auxiliary Space: O(1) as we are using an array of size 256
Note: The above programs don’t work for duplicate characters. To make them work for duplicate characters, find all the characters that are smaller (include equal this time also), do the same as above but, this time divide the rank so formed by p! where p is the count of occurrences of the repeating character.
Please Login to comment...