Lexicographic rank of a String

Last Updated : 14 Apr, 2026

Given a string s consisting of distinct lowercase characters, find its rank among all its permutations when sorted lexicographically.

Examples:

Input: s = "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 seen that the rank of s is 2.

Input: s = "string"
Output: 598

Input: s = "cba"
Output: Rank = 6

Try It Yourself
redirect icon

[Naive Approach] Generating all permutations - O(n * n!) Time and O(n) Space

The idea is to generate all the permutations in lexicographic order and store the rank of the current string. To generate all permutations, we first sort the string and then one by one generate lexicographically next permutation. After generating a permutation, check if the generated permutation is the same as the given string and return the rank of string.

Dry run for s = "bca":

  1. Original = "bca", after sorting the string becomes "abc" and initial rank is 1
  2. First permutation "abc" does not match "bca", next permutation becomes "acb" and rank becomes 2
  3. Second permutation "acb" does not match "bca", next permutation becomes "bac" and rank becomes 3
  4. Third permutation "bac" does not match "bca", next permutation becomes "bca" and rank becomes 4
  5. "bca" matches the original string, so the process stops and final rank = 4
C++
#include <algorithm>
#include <vector>
using namespace std;

long long findRank(string &s) {
    
    // Create a copy of the original 
    // string to keep it unchanged
    string original = s;
    
    // Sort the string to get the first 
    // permutation in lexicographic order
    sort(s.begin(), s.end());
    
    long long rank = 1;
    
    // Keep generating next permutation
    // until we find the original string
    while (s != original) {
        next_permutation(s.begin(), s.end());
        rank++;
    }
    
    return rank;
}

int main() {
    string s = "string";
    cout << findRank(s);
    return 0;
}
Java
import java.util.Arrays;

class GfG {

    static long findRank(String s) {

        // Create a copy of the original 
        // string to keep it unchanged
        String original = s;

        // Convert to character array for sorting and permutation
        char[] arr = s.toCharArray();

        // Sort the string to get the first 
        // permutation in lexicographic order
        Arrays.sort(arr);

        long rank = 1;

        // Keep generating next permutation
        // until we find the original string
        while (!String.valueOf(arr).equals(original)) {
            nextPermutation(arr);
            rank++;
        }

        return rank;
    }

    static void nextPermutation(char[] arr) {
        int i = arr.length - 2;
        while (i >= 0 && arr[i] >= arr[i + 1]) i--;

        if (i >= 0) {
            int j = arr.length - 1;
            while (arr[j] <= arr[i]) j--;
            char temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }

        reverse(arr, i + 1, arr.length - 1);
    }

    static void reverse(char[] arr, int start, int end) {
        while (start < end) {
            char temp = arr[start];
            arr[start++] = arr[end];
            arr[end--] = temp;
        }
    }

    public static void main(String[] args) {
        String s = "string";
        System.out.println(findRank(s));
    }
}
Python
def next_permutation(arr):
    
    # Find the rightmost element that is smaller than its next
    i = len(arr) - 2
    while i >= 0 and arr[i] >= arr[i + 1]:
        i -= 1
    
    # If no such element, we're at the last permutation
    if i < 0:
        return False
    
    # Find the smallest element greater than arr[i] to its right
    j = len(arr) - 1
    while arr[j] <= arr[i]:
        j -= 1
    
    # Swap them
    arr[i], arr[j] = arr[j], arr[i]
    
    # Reverse the suffix after position i
    arr[i + 1:] = reversed(arr[i + 1:])
    
    return True


def findRank(s):
    
    # Create a copy of the original 
    # string to keep it unchanged
    original = s
    
    # Sort the string to get the first 
    # permutation in lexicographic order
    arr = sorted(list(s))
    
    rank = 1
    
    # Keep generating next permutation
    # until we find the original string
    while ''.join(arr) != original:
        next_permutation(arr)
        rank += 1
    
    return rank


if __name__ == "__main__":
    s = "string"
    print(findRank(s))
C#
using System;

class GfG {

    static long findRank(string s) {

        // Create a copy of the original 
        // string to keep it unchanged
        string original = s;

        // Sort the string to get the first 
        // permutation in lexicographic order
        char[] arr = s.ToCharArray();
        Array.Sort(arr);

        long rank = 1;

        // Keep generating next permutation
        // until we find the original string
        while (new string(arr) != original) {
            nextPermutation(arr);
            rank++;
        }

        return rank;
    }

    static void nextPermutation(char[] arr) {
        int i = arr.Length - 2;
        while (i >= 0 && arr[i] >= arr[i + 1]) i--;

        if (i >= 0) {
            int j = arr.Length - 1;
            while (arr[j] <= arr[i]) j--;
            char temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }

        reverse(arr, i + 1, arr.Length - 1);
    }

    static void reverse(char[] arr, int start, int end) {
        while (start < end) {
            char temp = arr[start];
            arr[start++] = arr[end];
            arr[end--] = temp;
        }
    }

    static void Main(string[] args) {
        string s = "string";
        Console.WriteLine(findRank(s));
    }
}
JavaScript
function findRank(s) {

    // Create a copy of the original 
    // string to keep it unchanged
    let original = s;

    // Sort the string to get the first 
    // permutation in lexicographic order
    let arr = s.split('').sort();

    let rank = 1;

    // Keep generating next permutation
    // until we find the original string
    while (arr.join('') !== original) {
        nextPermutation(arr);
        rank++;
    }

    return rank;
}

function nextPermutation(arr) {
    let i = arr.length - 2;
    while (i >= 0 && arr[i] >= arr[i + 1]) i--;

    if (i >= 0) {
        let j = arr.length - 1;
        while (arr[j] <= arr[i]) j--;
        [arr[i], arr[j]] = [arr[j], arr[i]];
    }

    reverse(arr, i + 1, arr.length - 1);
}

function reverse(arr, start, end) {
    while (start < end) {
        [arr[start], arr[end]] = [arr[end], arr[start]];
        start++;
        end--;
    }
}

// Driver Code
let s = "string";
console.log(findRank(s));

Output
598

[Better Approach] Count Smaller Strings - O(n^2) Time and O(1) Space

We count smaller strings than the given string, and at the end return rank as one plus the count value.

Rank = Count of Smaller + 1
For example, for "cba", the 5 smaller strings are "abc", "acb", "bac", "bca" and "cab" and our result is 5 + 1.

How do we count smaller?

We first find count of smaller strings when the first character is replaced. For example, for "cba", if we fix the first character other than "c", we get 4 smaller strings. Now we do the same thing for second character which means, we count smaller strings when first is "c" and second is smaller than "b". We have 1 such string.

For a better understanding follow the below 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 fix 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 through the string from index i = 0 to n - 1.
  • For each character, count how many characters to its right are smaller than the current character.
  • For each such smaller character, calculate how many permutations can be formed with the remaining characters.
  • Add this value to the current rank.
  • After completing the iteration, add 1 to the final rank and return it as the answer.
C++
#include <iostream>
using namespace std;

// Factorial
long long fact(int n) { 
    long res = 1;
    for (int i = 2; i <= n; i++) { res *= i; }
    return res;
}

// A utility function to count
// smaller characters on right of arr[low]
int findSmallerInRight(string s, int low) {
    int countRight = 0;
    for (int i = low + 1; i < s.size(); ++i)
        if (s[i] < s[low])
            ++countRight;
    return countRight;
}

// A function to find rank of a string
// in all permutations of characters
long long findRank(string s) {
    int n = s.size();
    
    // 1 to be added to smaller count
    long long rank = 1;  
    int countRight;

    for (int i = 0; i < n; ++i) {

        // Count number of chars smaller than str[i]
        // from str[i+1] to str[len-1]
        countRight = findSmallerInRight(s, i);

        rank += countRight * fact(n - i - 1);
    }

    return rank;
}

int main() {
    string s = "string";
    cout << findRank(s);
    return 0;
}
Java
class GfG {

    // Factorial
    static long fact(int n) { 
        long res = 1;
        for (int i = 2; i <= n; i++) { res *= i; }
        return res;
    }

    // A utility function to count
    // smaller characters on right of arr[low]
    static int findSmallerInRight(String s, int low) {
        int countRight = 0;
        for (int i = low + 1; i < s.length(); ++i)
            if (s.charAt(i) < s.charAt(low))
                ++countRight;
        return countRight;
    }

    // A function to find rank of a string
    // in all permutations of characters
    static long findRank(String s) {
        int n = s.length();
        
        // 1 to be added to smaller count
        long rank = 1;  
        int countRight;

        for (int i = 0; i < n; ++i) {

            // Count number of chars smaller than str[i]
            // from str[i+1] to str[len-1]
            countRight = findSmallerInRight(s, i);

            rank += countRight * fact(n - i - 1);
        }

        return rank;
    }

    public static void main(String[] args) {
        String s = "string";
        System.out.println(findRank(s));
    }
}
Python
# Factorial
def fact(n): 
    res = 1
    for i in range(2, n + 1):
        res *= i
    return res

# A utility function to count
# smaller characters on right of arr[low]
def findSmallerInRight(s, low):
    countRight = 0
    for i in range(low + 1, len(s)):
        if s[i] < s[low]:
            countRight += 1
    return countRight

# A function to find rank of a string
# in all permutations of characters
def findRank(s):
    n = len(s)
    
    # 1 to be added to smaller count
    rank = 1  
    for i in range(n):

        # Count number of chars smaller than str[i]
        # from str[i+1] to str[len-1]
        countRight = findSmallerInRight(s, i)

        rank += countRight * fact(n - i - 1)

    return rank

if __name__ == "__main__":
    s = "string"
    print(findRank(s))
C#
using System;

class GfG {

    // Factorial
    static long fact(int n) { 
        long res = 1;
        for (int i = 2; i <= n; i++) { res *= i; }
        return res;
    }

    // A utility function to count
    // smaller characters on right of arr[low]
    static int findSmallerInRight(string s, int low) {
        int countRight = 0;
        for (int i = low + 1; i < s.Length; ++i)
            if (s[i] < s[low])
                ++countRight;
        return countRight;
    }

    // A function to find rank of a string
    // in all permutations of characters
    static long findRank(string s) {
        int n = s.Length;
        
        // 1 to be added to smaller count
        long rank = 1;  
        int countRight;

        for (int i = 0; i < n; ++i) {

            // Count number of chars smaller than str[i]
            // from str[i+1] to str[len-1]
            countRight = findSmallerInRight(s, i);

            rank += countRight * fact(n - i - 1);
        }

        return rank;
    }

    static void Main(string[] args) {
        string s = "string";
        Console.WriteLine(findRank(s));
    }
}
JavaScript
// Factorial
function fact(n) { 
    let res = 1;
    for (let i = 2; i <= n; i++) { res *= i; }
    return res;
}

// A utility function to count
// smaller characters on right of arr[low]
function findSmallerInRight(s, low) {
    let countRight = 0;
    for (let i = low + 1; i < s.length; ++i)
        if (s[i] < s[low])
            ++countRight;
    return countRight;
}

// A function to find rank of a string
// in all permutations of characters
function findRank(s) {
    let n = s.length;
    
    // 1 to be added to smaller count
    let rank = 1;  
    let countRight;

    for (let i = 0; i < n; ++i) {

        // Count number of chars smaller than str[i]
        // from str[i+1] to str[len-1]
        countRight = findSmallerInRight(s, i);

        rank += countRight * fact(n - i - 1);
    }

    return rank;
}

// Driver Code
let s = "string";
console.log(findRank(s));

Output
598

Note: We can avoid repeated computation of factorial by first calculating n! and then successively dividing by (n - i) to obtain the remaining factorial values during iteration.

[Expected Approach] Using Frequency Array - O(n) Time and O(1) Space

Create a frequency array to store character counts and convert it into a cumulative array to efficiently find how many characters are smaller than the current character, updating it after each index during iteration.

Dry run for s = "string":

  • i = 0, character 's', smaller characters are g, i, n, r so count = 4, remaining = 5! = 120, rank becomes 1 + (4 × 120) = 481
  • i = 1, character 't', smaller characters are g, i, n, r so count = 4, remaining = 4! = 24, rank becomes 481 + (4 × 24) = 577
  • i = 2, character 'r', smaller characters are g, i, n so count = 3, remaining = 3! = 6, rank becomes 577 + (3 × 6) = 595
  • i = 3, character 'i', smaller character is g so count = 1, remaining = 2! = 2, rank becomes 595 + (1 × 2) = 597
  • i = 4, character 'n', smaller character is g so count = 1, remaining = 1! = 1, rank becomes 597 + (1 × 1) = 598
  • i = 5, character 'g', smaller characters = 0, remaining = 0! = 1, rank remains 598
C++
#include <iostream>
using namespace std;

// Factorial
long long fact(int n) { 
    long long res = 1;
    for (int i = 2; i <= n; i++) { res *= i; }
    return res;
}

// A function to find rank of a string in all permutations
// of characters
long long findRank(string &s)
{
    int n = s.size();
    long long mul = fact(n);
    long long rank = 1;
    
    // Using a vector of size 26 for lowercase letters
    vector<int> count(26, 0);
    
    // Populate the count array for each character in string
    for (int i = 0; i < n; ++i) {
        ++count[s[i] - 'a'];
    }
    
    // Convert count to cumulative sum
    for (int i = 1; i < 26; ++i) {
        count[i] += count[i - 1];
    }
    
    for (int i = 0; i < n; ++i) {
        mul /= (n - i);
        
        // Get index of current character in count array
        int charIndex = s[i] - 'a';
        
        // Add count of characters smaller than current character
        if (charIndex > 0) {
            rank += count[charIndex - 1] * mul;
        }
        
        // Update count array
        for (int j = charIndex; j < 26; ++j) {
            --count[j];
        }
    }
    
    return rank;
}

int main() {
    string s = "string";
    cout << findRank(s);
    return 0;
}
Java
class GfG {

    // Factorial
    static long fact(int n) { 
        long res = 1;
        for (int i = 2; i <= n; i++) { res *= i; }
        return res;
    }

    // A function to find rank of a string in all permutations
    // of characters
    static long findRank(String s) {
        int n = s.length();
        long mul = fact(n);
        long rank = 1;

        // Using a vector of size 26 for lowercase letters
        int[] count = new int[26];

        // Populate the count array for each character in string
        for (int i = 0; i < n; ++i) {
            ++count[s.charAt(i) - 'a'];
        }

        // Convert count to cumulative sum
        for (int i = 1; i < 26; ++i) {
            count[i] += count[i - 1];
        }

        for (int i = 0; i < n; ++i) {
            mul /= (n - i);

            // Get index of current character in count array
            int charIndex = s.charAt(i) - 'a';

            // Add count of characters smaller than current character
            if (charIndex > 0) {
                rank += count[charIndex - 1] * mul;
            }

            // Update count array
            for (int j = charIndex; j < 26; ++j) {
                --count[j];
            }
        }

        return rank;
    }

    public static void main(String[] args) {
        String s = "string";
        System.out.println(findRank(s));
    }
}
Python
# Factorial
def fact(n): 
    res = 1
    for i in range(2, n + 1):
        res *= i
    return res

# A function to find rank of a string in all permutations
# of characters
def findRank(s):
    n = len(s)
    mul = fact(n)
    rank = 1

    # Using a vector of size 26 for lowercase letters
    count = [0] * 26

    # Populate the count array for each character in string
    for i in range(n):
        count[ord(s[i]) - ord('a')] += 1

    # Convert count to cumulative sum
    for i in range(1, 26):
        count[i] += count[i - 1]

    for i in range(n):
        mul //= (n - i)

        # Get index of current character in count array
        charIndex = ord(s[i]) - ord('a')

        # Add count of characters smaller than current character
        if charIndex > 0:
            rank += count[charIndex - 1] * mul

        # Update count array
        for j in range(charIndex, 26):
            count[j] -= 1

    return rank

if __name__ == "__main__":
    s = "string"
    print(findRank(s))
C#
using System;

class GfG {

    // Factorial
    static long fact(int n) { 
        long res = 1;
        for (int i = 2; i <= n; i++) { res *= i; }
        return res;
    }

    // A function to find rank of a string in all permutations
    // of characters
    static long findRank(string s) {
        int n = s.Length;
        long mul = fact(n);
        long rank = 1;

        // Using a vector of size 26 for lowercase letters
        int[] count = new int[26];

        // Populate the count array for each character in string
        for (int i = 0; i < n; ++i) {
            ++count[s[i] - 'a'];
        }

        // Convert count to cumulative sum
        for (int i = 1; i < 26; ++i) {
            count[i] += count[i - 1];
        }

        for (int i = 0; i < n; ++i) {
            mul /= (n - i);

            // Get index of current character in count array
            int charIndex = s[i] - 'a';

            // Add count of characters smaller than current character
            if (charIndex > 0) {
                rank += count[charIndex - 1] * mul;
            }

            // Update count array
            for (int j = charIndex; j < 26; ++j) {
                --count[j];
            }
        }

        return rank;
    }

    static void Main(string[] args) {
        string s = "string";
        Console.WriteLine(findRank(s));
    }
}
JavaScript
// Factorial
function fact(n) { 
    let res = 1;
    for (let i = 2; i <= n; i++) { res *= i; }
    return res;
}

// A function to find rank of a string in all permutations
// of characters
function findRank(s) {
    let n = s.length;
    let mul = fact(n);
    let rank = 1;

    // Using a vector of size 26 for lowercase letters
    let count = new Array(26).fill(0);

    // Populate the count array for each character in string
    for (let i = 0; i < n; ++i) {
        ++count[s.charCodeAt(i) - 'a'.charCodeAt(0)];
    }

    // Convert count to cumulative sum
    for (let i = 1; i < 26; ++i) {
        count[i] += count[i - 1];
    }

    for (let i = 0; i < n; ++i) {
        mul = Math.floor(mul / (n - i));

        // Get index of current character in count array
        let charIndex = s.charCodeAt(i) - 'a'.charCodeAt(0);

        // Add count of characters smaller than current character
        if (charIndex > 0) {
            rank += count[charIndex - 1] * mul;
        }

        // Update count array
        for (let j = charIndex; j < 26; ++j) {
            --count[j];
        }
    }

    return rank;
}

// Driver Code
let s = "string";
console.log(findRank(s));

Output
598

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. 

Comment