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: 598
Input: 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;
int fact( int n) {
if (n <= 1) {
return 1;
}
return n * fact(n - 1);
}
int findRank(string str) {
int n = str.length();
int rank = 1;
for ( int i = 0; i < n; i++) {
int count = 0;
for ( int j = i + 1; j < n; j++) {
if (str[i] > str[j]) {
count++;
}
}
rank += count * fact(n - i - 1);
}
return rank;
}
int main() {
string str = "string" ;
cout << findRank(str) << endl;
return 0;
}
|
Java
import java.util.Arrays;
public class LexicographicRank {
static int fact( int n)
{
if (n <= 1 ) {
return 1 ;
}
return n * fact(n - 1 );
}
static int findRank(String str)
{
int n = str.length();
int rank = 1 ;
for ( int i = 0 ; i < n; i++) {
int count = 0 ;
for ( int j = i + 1 ; j < n; j++) {
if (str.charAt(i) > str.charAt(j)) {
count++;
}
}
rank += count * fact(n - i - 1 );
}
return rank;
}
public static void main(String[] args)
{
String str = "string" ;
System.out.println(findRank(str));
}
}
|
Python3
def fact(n):
if n < = 1 :
return 1
return n * fact(n - 1 )
def findRank(s):
n = len (s)
rank = 1
for i in range (n):
count = 0
for j in range (i + 1 , n):
if s[i] > s[j]:
count + = 1
rank + = count * fact(n - i - 1 )
return rank
def main():
s = "string"
print (findRank(s))
return 0
main()
|
C#
using System;
class Program {
static int Fact( int n)
{
if (n <= 1) {
return 1;
}
return n * Fact(n - 1);
}
static int FindRank( string str)
{
int n = str.Length;
int rank = 1;
for ( int i = 0; i < n; i++) {
int count = 0;
for ( int j = i + 1; j < n; j++) {
if (str[i] > str[j]) {
count++;
}
}
rank += count * Fact(n - i - 1);
}
return rank;
}
static void Main( string [] args)
{
string str = "string" ;
Console.WriteLine(FindRank(str));
}
}
|
Javascript
function fact(n) {
if (n <= 1) {
return 1;
}
return n * fact(n - 1);
}
function findRank(str) {
const n = str.length;
let rank = 1;
for (let i = 0; i < n; i++) {
let count = 0;
for (let j = i + 1; j < n; j++) {
if (str[i] > str[j]) {
count++;
}
}
rank += count * fact(n - i - 1);
}
return rank;
}
function main() {
const str = "string" ;
console.log(findRank(str));
}
main();
|
Time Complexity: O(N2) 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++
#include <bits/stdc++.h>
using namespace std;
int fact( int n) {
return (n <= 1) ? 1 : n * fact(n - 1);
}
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;
}
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;
countRight = findSmallerInRight(str, i, len - 1);
rank += countRight * mul;
}
return rank;
}
int main()
{
string str = "string" ;
cout << findRank(str);
return 0;
}
|
C
#include <stdio.h>
#include <string.h>
int fact( int n) {
return (n <= 1) ? 1 : n * fact(n - 1);
}
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;
}
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;
countRight = findSmallerInRight(str, i, len - 1);
rank += countRight * mul;
}
return rank;
}
int main()
{
char str[] = "string" ;
printf ( "%d" , findRank(str));
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
static int fact( int n)
{
return (n <= 1 ) ? 1 : n * fact(n - 1 );
}
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;
}
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;
countRight
= findSmallerInRight(str, i, len - 1 );
rank += countRight * mul;
}
return rank;
}
public static void main(String[] args)
{
String str = "string" ;
System.out.println(findRank(str));
}
}
|
Python3
def fact(n):
f = 1
while n > = 1 :
f = f * n
n = n - 1
return f
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
def findRank(st):
ln = len (st)
mul = fact(ln)
rank = 1
i = 0
while i < ln:
mul = mul / / (ln - i)
countRight = findSmallerInRight(st, i, ln - 1 )
rank = rank + countRight * mul
i = i + 1
return rank
if __name__ = = '__main__' :
st = "string"
print (findRank(st))
|
C#
using System;
class GFG {
static int fact( int n)
{
return (n <= 1) ? 1 : n * fact(n - 1);
}
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;
}
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;
countRight
= findSmallerInRight(str, i, len - 1);
rank += countRight * mul;
}
return rank;
}
public static void Main()
{
string str = "string" ;
Console.Write(findRank(str));
}
}
|
Javascript
<script>
function fact(n)
{
return (n <= 1) ? 1 : n * fact(n - 1);
}
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;
}
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;
countRight = findSmallerInRight(str, i, len - 1);
rank += countRight * mul;
}
return rank;
}
let str = "string" ;
document.write(findRank(str));
</script>
|
PHP
<?php
function fact( $n )
{
return ( $n <= 1) ? 1 : $n * fact( $n - 1);
}
function findSmallerInRight( $str , $low , $high )
{
$countRight = 0;
for ( $i = $low + 1; $i <= $high ; ++ $i )
if ( $str [ $i ] < $str [ $low ])
++ $countRight ;
return $countRight ;
}
function findRank ( $str )
{
$len = strlen ( $str );
$mul = fact( $len );
$rank = 1;
for ( $i = 0; $i < $len ; ++ $i )
{
$mul /= $len - $i ;
$countRight = findSmallerInRight( $str , $i ,
$len - 1);
$rank += $countRight * $mul ;
}
return $rank ;
}
$str = "string" ;
echo findRank( $str );
?>
|
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++
#include <bits/stdc++.h>
using namespace std;
#define MAX_CHAR 256
int fact( int n) {
return (n <= 1) ? 1 : n * fact(n - 1);
}
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];
}
void updatecount( int * count, char ch)
{
int i;
for (i = ch; i < MAX_CHAR; ++i)
--count[i];
}
int findRank(string str)
{
int len = str.size();
int mul = fact(len);
int rank = 1, i;
int count[MAX_CHAR] = { 0 };
populateAndIncreaseCount(count, str);
for (i = 0; i < len; ++i) {
mul /= len - i;
rank += count[str[i] - 1] * mul;
updatecount(count, str[i]);
}
return rank;
}
int main()
{
string str = "string" ;
cout << findRank(str);
return 0;
}
|
C
#include <stdio.h>
#include <string.h>
#define MAX_CHAR 256
int fact( int n) {
return (n <= 1) ? 1 : n * fact(n - 1);
}
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];
}
void updatecount( int * count, char ch)
{
int i;
for (i = ch; i < MAX_CHAR; ++i)
--count[i];
}
int findRank( char * str)
{
int len = strlen (str);
int mul = fact(len);
int rank = 1, i;
int count[MAX_CHAR] = { 0 };
populateAndIncreaseCount(count, str);
for (i = 0; i < len; ++i) {
mul /= len - i;
rank += count[str[i] - 1] * mul;
updatecount(count, str[i]);
}
return rank;
}
int main()
{
char str[] = "string" ;
printf ( "%d" , findRank(str));
return 0;
}
|
Java
class GFG {
static int MAX_CHAR = 256 ;
static int fact( int n)
{
return (n <= 1 ) ? 1 : n * fact(n - 1 );
}
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 ];
}
static void updatecount( int [] count, char ch)
{
int i;
for (i = ch; i < MAX_CHAR; ++i)
--count[i];
}
static int findRank(String str)
{
int len = str.length();
int mul = fact(len);
int rank = 1 , i;
int count[] = new int [MAX_CHAR];
populateAndIncreaseCount(count, str);
for (i = 0 ; i < len; ++i) {
mul /= len - i;
rank += count[str.charAt(i) - 1 ] * mul;
updatecount(count, str.charAt(i));
}
return rank;
}
public static void main(String args[])
{
String str = "string" ;
System.out.println(findRank(str));
}
}
|
Python3
MAX_CHAR = 256
count = [ 0 ] * (MAX_CHAR + 1 )
def fact(n):
return 1 if (n < = 1 ) else (n * fact(n - 1 ))
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 ]
def updatecount(ch):
for i in range ( ord (ch), MAX_CHAR):
count[i] - = 1
def findRank( str ):
len1 = len ( str )
mul = fact(len1)
rank = 1
populateAndIncreaseCount( str )
for i in range (len1):
mul = mul / / (len1 - i)
rank + = count[ ord ( str [i]) - 1 ] * mul
updatecount( str [i])
return rank
if __name__ = = '__main__' :
str = "string"
print (findRank( str ))
|
C#
using System;
class GFG {
static int MAX_CHAR = 256;
static int fact( int n)
{
return (n <= 1) ? 1 : n * fact(n - 1);
}
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];
}
static void updatecount( int [] count, char ch)
{
int i;
for (i = ch; i < MAX_CHAR; ++i)
--count[i];
}
static int findRank( char [] str)
{
int len = str.Length;
int mul = fact(len);
int rank = 1, i;
int [] count = new int [MAX_CHAR];
populateAndIncreaseCount(count, str);
for (i = 0; i < len; ++i) {
mul /= len - i;
rank += count[str[i] - 1] * mul;
updatecount(count, str[i]);
}
return rank;
}
public static void Main(String[] args)
{
char [] str = "string" .ToCharArray();
Console.WriteLine(findRank(str));
}
}
|
Javascript
<script>
let MAX_CHAR = 256;
function fact(n)
{
return (n <= 1) ? 1 : n * fact(n - 1);
}
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];
}
function updatecount(count,ch)
{
let i;
for (i = ch.charCodeAt(0); i < MAX_CHAR; ++i)
--count[i];
}
function findRank(str)
{
let len = str.length;
let mul = fact(len);
let rank = 1, i;
let count = new Array(MAX_CHAR);
for (let i = 0; i < count.length; i++)
{
count[i] = 0;
}
populateAndIncreaseCount(count, str);
for (i = 0; i < len; ++i) {
mul = Math.floor(mul/(len - i));
rank += count[str[i].charCodeAt(0) - 1] * mul;
updatecount(count, str[i]);
}
return rank;
}
let str= "string" .split( "" );
document.write(findRank(str));
</script>
|
PHP
<?php
$MAX_CHAR =256;
function fact( $n )
{
return ( $n <= 1) ? 1 : $n * fact( $n - 1);
}
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];
}
function updatecount(& $count , $ch )
{
global $MAX_CHAR ;
for ( $i = ord( $ch ); $i < $MAX_CHAR ; ++ $i )
-- $count [ $i ];
}
function findRank( $str )
{
global $MAX_CHAR ;
$len = strlen ( $str );
$mul = fact( $len );
$rank = 1;
$count = array_fill (0, $MAX_CHAR + 1, 0);
populateAndIncreaseCount( $count , $str );
for ( $i = 0; $i < $len ; ++ $i )
{
$mul = (int)( $mul /( $len - $i ));
$rank += $count [ord( $str [ $i ]) - 1] * $mul ;
updatecount( $count , $str [ $i ]);
}
return $rank ;
}
$str = "string" ;
echo findRank( $str );
?>
|
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.
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
16 Oct, 2023
Like Article
Save Article