std::next_permutation | Overview and Implementation in C++
This post discusses std::next_permutation, which can be used to find the lexicographically greater 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 next permutation in lexicographic order for string 123 is 132.
The STL provides std::next_permutation, which returns the next permutation in lexicographic order by in-place rearranging the specified object as a lexicographically greater permutation. The function returns true if the next higher 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 first permutation.
std::next_permutation generates the next permutation in just linear time, and it can also handle repeated characters and generates distinct permutations. Its usage can be seen below:
|
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 a natural order before calling std::next_permutation inside a loop to print all permutations, not just the ones that follow specified string lexicographically */ // std::sort(begin(s), end(s)); // find all lexicographically greater permutations using // std::next_permutation while (1) { // print the current permutation std::cout << s << " "; // find the next permutation in lexicographic order if (!std::next_permutation(begin(s), end(s))) { break; } } return 0; } |
Output:
231 312 321
We can also implement our next_permutation method. The following in-place algorithm lexicographically generates the next permutation after a given permutation:
- Find the largest index
isuch thats[i-1]is less thans[i]. - If
iis the first index of the string, the permutation is the last permutation; otherwise,s[i…n-1]is sorted in reverse order, i.e.,s[i-1] < s[i] >= s[i+1] >= s[i+2] >= … >= s[n-1]. - Find the highest index
jto the right of indexisuch thats[j]is greater thans[i-1]and swap the character at indexi-1with indexj. - Reverse substring
s[i…n-1]and return true.
The algorithm can be implemented as follows 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 |
#include <iostream> #include <algorithm> // Function to rearrange the specified string as lexicographically greater // permutation. It returns false if the string cannot be rearranged as a // lexicographically greater permutation; otherwise, it returns true. bool nextPermutation(std::string &s, int n) { // Find the largest index `i` such that `s[i-1]` is less than `s[i]` int i = n-1; while (s[i-1] >= s[i]) { // if `i` is the first index of the string, we are already at the last // possible permutation (string is sorted in reverse order) if (--i == 0) { return false; } } // If we reach here, substring `s[i…n-1]` is sorted in reverse order. // Find the highest index `j` to the right of index `i` such that `s[j] > s[i-1]`. int j = n-1; while (j > i && s[j] <= s[i-1]) { 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(begin(s), end(s)); // find all lexicographically greater permutations using // std::next_permutation while (1) { // print the current permutation std::cout << s << " "; // find the next permutation in lexicographic order if (!nextPermutation(s, s.length())) { break; } } return 0; } |
Output:
231 312 321
Since there are n! permutations for a string of length n, and each permutation takes O(n) time, the time complexity of the above solution is O(n.n!). The best case happens when the string contains all repeated characters, and the worst-case happens when the string contains all distinct elements.
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 :)