![]() |
VOOZH | about |
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: 598Input: s = "cba"
Output: Rank = 6
Table of Content
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":
598
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:
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.
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":
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.