Lexicographic rank of a string

Given a string, find its rank among all its permutations sorted lexicographically. For example, rank of “abc” is 1, rank of “acb” is 2, and rank of “cba” is 6.

Examples:

Input : str[] = "acb"
Output : Rank = 2

Input : str[] = "string"
Output : Rank = 598

Input : str[] = "cba"
Output : Rank = 6

For simplicity, let us assume that the string does not contain any duplicated characters.

One simple solution is to initialize rank as 1, generate all permutations in lexicographic order. After generating a permutation, check if the generated permutation is same as given string, if same, then return rank, if not, then increment the rank by 1. The time complexity of this solution will be exponential in worst case. Following is an efficient solution.

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



R X X X X X
I X X X X X
N X X X X X
G X X X X X

Now let us 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 fix N and repeat the same process for G, rank is 4*5! + 4*4! + 3*3! + 1*2! + 1*1! + 0*0!

Rank = 4*5! + 4*4! + 3*3! + 1*2! + 1*1! + 0*0! = 597

Note that 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

Below is the implementation of above approach:

C++



filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to find lexicographic rank
// of a string
#include <bits/stdc++.h>
#include <string.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(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]
        // fron str[i+1] to str[len-1]
        countRight = findSmallerInRight(str, i, len - 1);
  
        rank += countRight * mul;
    }
  
    return rank;
}
  
// Driver program to test above function
int main()
{
    char str[] = "string";
    cout << findRank(str);
    return 0;
}
  
// This code is contributed
// by Akanksha Rai

chevron_right


C

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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]
        // fron str[i+1] to str[len-1]
        countRight = findSmallerInRight(str, i, len - 1);
  
        rank += countRight * mul;
    }
  
    return rank;
}
  
// Driver program to test above function
int main()
{
    char str[] = "string";
    printf("%d", findRank(str));
    return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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 program to test above function
    public static void main(String[] args)
    {
        String str = "string";
        System.out.println(findRank(str));
    }
}
  
// This code is contributed by Nikita Tiwari.

chevron_right


Python

filter_none

edit
close

play_arrow

link
brightness_4
code

# 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] fron str[i + 1] to
        # str[len-1]
        countRight = findSmallerInRight(st, i, ln-1)
   
        rank = rank + countRight * mul
        i = i + 1
          
    return rank
      
      
# Driver program to test above function
st = "string"
print (findRank(st))
  
# This code is contributed by Nikita Tiwari.

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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 program to test above function
    public static void Main()
    {
        string str = "string";
        Console.Write(findRank(str));
    }
}
  
// This code is contributed nitin mittal.

chevron_right


PHP

filter_none

edit
close

play_arrow

link
brightness_4
code

<?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] fron 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
?>

chevron_right



Output:

598

The time complexity of the above solution is O(n^2). We can reduce the time complexity to O(n) by creating an auxiliary array of size 256. See following code.

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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, 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]
        // fron 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 program to test above function
int main()
{
    char str[] = "string";
    cout << findRank(str);
    return 0;
}
  
// This is code is contributed by rathbhupendra

chevron_right


C

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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]
        // fron 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 program to test above function
int main()
{
    char str[] = "string";
    printf("%d", findRank(str));
    return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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, 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]
            // fron 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();
        System.out.println(findRank(str));
    }
}
  
// This code has been contributed by 29AjayKumar

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# 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]
        # fron 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
str = "string";
print(findRank(str));
  
# This is code is contributed by chandan_jnu

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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]
            // fron 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 */

chevron_right


PHP

filter_none

edit
close

play_arrow

link
brightness_4
code

<?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]
        // fron 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
?>

chevron_right


Output:

598

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 write comments if you find anything incorrect, or you want to share more information about the topic discussed above.



My Personal Notes arrow_drop_up