std::prev_permutation | Overview and Implementation in C++
This post discusses std::prev_permutation, which can be used to find the lexicographically smaller permutations of a string.
The lexicographic or lexicographical order (aka lexical order, dictionary order, alphabetical order) means that the words are arranged as they are presumed to appear in a dictionary. For example, the previous permutation in lexicographic order for string 213 is 132.
The STL provides std::prev_permutation, which returns the previous permutation in lexicographic order by in-place rearranging the specified object as a lexicographically smaller permutation. The function returns true if the previous permutation exists; otherwise, it returns false to indicate that the object is already at the highest possible permutation and reset the range according to the last permutation.
std::prev_permutation generates the previous permutation in mere linear time and handles repeated characters to generate the distinct permutations. Following is the C++ program which demonstrates its usage:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include <iostream> #include <algorithm> int main() { std::string s = "231"; /* Optional: sort the string in reverse order before calling std::prev_permutation to print all permutations, not just the ones that follow specified string lexicographically */ // std::sort(rbegin(s), rend(s)); // find all lexicographically smaller permutations using // std::prev_permutation while (1) { // print the current permutation std::cout << s << " "; // find the previous permutation in lexicographic order if (!std::prev_permutation(begin(s), end(s))) { break; } } return 0; } |
Output:
231 213 132 123
We can also implement our prev_permutation method. The following in-place algorithm lexicographically generates the previous permutation after a given permutation:
- Find the largest index
isuch thats[i-1] > s[i]. - If
iis the first index of the string, the permutation is the first permutation; otherwise,s[i…n-1]is sorted in natural order, i.e.,s[i-1] > s[i] <= s[i+1] <= s[i+2] <= … <= s[n-1]. - Find the highest index
jsuch thatj >= iands[j] < s[i-1]and swap the character at indexi-1with indexj. - Reverse substring
s[i…n-1]and return true.
The implementation can be seen below in C++:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#include <iostream> #include <algorithm> // Function to rearrange the specified string as lexicographically smaller // permutation. It returns false if the string cannot be rearranged as a // lexicographically smaller permutation; otherwise, it returns true. bool prevPermutation(std::string &s, int n) { // Find the largest index `i` such that `s[i-1]` is more than s[i] int i = n-1; while (i > 0 && s[i-1] <= s[i]) { // Return false if `i` is at the first index of the string. // This means we are already at the lowest possible permutation if (--i == 0) { return false; } } /* Substring `s[i…n-1]` is now sorted in a natural order */ // Find the highest index `j` such that `j >= i` and `s[j] < s[i-1]` int j = i; while (j < n && s[j] <= s[i-1]) { j++; } j--; // Swap character at index `i-1` with index `j` std::swap(s[i-1], s[j]); // Reverse substring `s[i…n-1]`and return true std::reverse (s.begin() + i, s.end()); return true; } int main() { std::string s = "231"; // std::sort(rbegin(s), rend(s)); // find all lexicographically smaller permutations using // std::prev_permutation while (1) { // print the current permutation std::cout << s << " "; // find the previous permutation in lexicographic order if (!prevPermutation(s, s.length())) { break; } } return 0; } |
Output:
231 213 132 123
Since there are n! permutations for a string of length n, and each permutation takes linear time, the time complexity of the above solution is O(n.n!). The worst case happens when the string contains all distinct elements, and the best-case happens when the string contains all repeated characters.
Also See:
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)