Closest greater lexicographical permutation

Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
2
down vote
favorite
I wrote this algorithm to find the closest greater lexicographical permutation.
Given a word w, it rearranges the letters to construct another word in such a way that this new word is lexicographically greater than w. From all the possibilities the one that produces the smallest lexicographical word is chosen.
Any ideas to improve the algorithm, it's readability, or the style in general?
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
string closest_greater_lexicographical_permutation(string w)
for (auto rit = next(w.rbegin()); rit!=w.rend(); ++rit)
auto it = prev(rit.base());
auto lowest_max = it;
for (auto it_max = next(it); it_max!=w.end(); ++it_max)
if (string(1,*it_max) > string(1,*it))
if (lowest_max == it)
lowest_max = it_max;
else if (string(1,*it_max) < string(1,*lowest_max))
lowest_max = it_max;
if (lowest_max != it)
iter_swap(lowest_max, it);
sort(next(it),w.end(),
(auto lhs, auto rhs)
return string(1,lhs) < string(1,rhs);
);
return w;
return w;
c++ algorithm
add a comment |Â
up vote
2
down vote
favorite
I wrote this algorithm to find the closest greater lexicographical permutation.
Given a word w, it rearranges the letters to construct another word in such a way that this new word is lexicographically greater than w. From all the possibilities the one that produces the smallest lexicographical word is chosen.
Any ideas to improve the algorithm, it's readability, or the style in general?
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
string closest_greater_lexicographical_permutation(string w)
for (auto rit = next(w.rbegin()); rit!=w.rend(); ++rit)
auto it = prev(rit.base());
auto lowest_max = it;
for (auto it_max = next(it); it_max!=w.end(); ++it_max)
if (string(1,*it_max) > string(1,*it))
if (lowest_max == it)
lowest_max = it_max;
else if (string(1,*it_max) < string(1,*lowest_max))
lowest_max = it_max;
if (lowest_max != it)
iter_swap(lowest_max, it);
sort(next(it),w.end(),
(auto lhs, auto rhs)
return string(1,lhs) < string(1,rhs);
);
return w;
return w;
c++ algorithm
1
Are you intentionally eschewingstd::next_permutation()? If so, consider marking this with reinventing-the-wheel.
â Toby Speight
Jan 18 at 18:59
Oh, and what's it supposed to do if there is no valid result?
â Toby Speight
Jan 18 at 19:02
If there is no valid result it just returns the same string @TobySpeight
â WooWapDaBug
Jan 18 at 22:14
@TobySpeight Oh, i didn't know that existed, thank you for pointing it out!
â WooWapDaBug
Jan 18 at 22:16
1
as an auto-correct you might check en.cppreference.com/w/cpp/algorithm/next_permutation
â papagaga
Jan 18 at 23:21
add a comment |Â
up vote
2
down vote
favorite
up vote
2
down vote
favorite
I wrote this algorithm to find the closest greater lexicographical permutation.
Given a word w, it rearranges the letters to construct another word in such a way that this new word is lexicographically greater than w. From all the possibilities the one that produces the smallest lexicographical word is chosen.
Any ideas to improve the algorithm, it's readability, or the style in general?
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
string closest_greater_lexicographical_permutation(string w)
for (auto rit = next(w.rbegin()); rit!=w.rend(); ++rit)
auto it = prev(rit.base());
auto lowest_max = it;
for (auto it_max = next(it); it_max!=w.end(); ++it_max)
if (string(1,*it_max) > string(1,*it))
if (lowest_max == it)
lowest_max = it_max;
else if (string(1,*it_max) < string(1,*lowest_max))
lowest_max = it_max;
if (lowest_max != it)
iter_swap(lowest_max, it);
sort(next(it),w.end(),
(auto lhs, auto rhs)
return string(1,lhs) < string(1,rhs);
);
return w;
return w;
c++ algorithm
I wrote this algorithm to find the closest greater lexicographical permutation.
Given a word w, it rearranges the letters to construct another word in such a way that this new word is lexicographically greater than w. From all the possibilities the one that produces the smallest lexicographical word is chosen.
Any ideas to improve the algorithm, it's readability, or the style in general?
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
string closest_greater_lexicographical_permutation(string w)
for (auto rit = next(w.rbegin()); rit!=w.rend(); ++rit)
auto it = prev(rit.base());
auto lowest_max = it;
for (auto it_max = next(it); it_max!=w.end(); ++it_max)
if (string(1,*it_max) > string(1,*it))
if (lowest_max == it)
lowest_max = it_max;
else if (string(1,*it_max) < string(1,*lowest_max))
lowest_max = it_max;
if (lowest_max != it)
iter_swap(lowest_max, it);
sort(next(it),w.end(),
(auto lhs, auto rhs)
return string(1,lhs) < string(1,rhs);
);
return w;
return w;
c++ algorithm
asked Jan 18 at 14:25
WooWapDaBug
348214
348214
1
Are you intentionally eschewingstd::next_permutation()? If so, consider marking this with reinventing-the-wheel.
â Toby Speight
Jan 18 at 18:59
Oh, and what's it supposed to do if there is no valid result?
â Toby Speight
Jan 18 at 19:02
If there is no valid result it just returns the same string @TobySpeight
â WooWapDaBug
Jan 18 at 22:14
@TobySpeight Oh, i didn't know that existed, thank you for pointing it out!
â WooWapDaBug
Jan 18 at 22:16
1
as an auto-correct you might check en.cppreference.com/w/cpp/algorithm/next_permutation
â papagaga
Jan 18 at 23:21
add a comment |Â
1
Are you intentionally eschewingstd::next_permutation()? If so, consider marking this with reinventing-the-wheel.
â Toby Speight
Jan 18 at 18:59
Oh, and what's it supposed to do if there is no valid result?
â Toby Speight
Jan 18 at 19:02
If there is no valid result it just returns the same string @TobySpeight
â WooWapDaBug
Jan 18 at 22:14
@TobySpeight Oh, i didn't know that existed, thank you for pointing it out!
â WooWapDaBug
Jan 18 at 22:16
1
as an auto-correct you might check en.cppreference.com/w/cpp/algorithm/next_permutation
â papagaga
Jan 18 at 23:21
1
1
Are you intentionally eschewing
std::next_permutation()? If so, consider marking this with reinventing-the-wheel.â Toby Speight
Jan 18 at 18:59
Are you intentionally eschewing
std::next_permutation()? If so, consider marking this with reinventing-the-wheel.â Toby Speight
Jan 18 at 18:59
Oh, and what's it supposed to do if there is no valid result?
â Toby Speight
Jan 18 at 19:02
Oh, and what's it supposed to do if there is no valid result?
â Toby Speight
Jan 18 at 19:02
If there is no valid result it just returns the same string @TobySpeight
â WooWapDaBug
Jan 18 at 22:14
If there is no valid result it just returns the same string @TobySpeight
â WooWapDaBug
Jan 18 at 22:14
@TobySpeight Oh, i didn't know that existed, thank you for pointing it out!
â WooWapDaBug
Jan 18 at 22:16
@TobySpeight Oh, i didn't know that existed, thank you for pointing it out!
â WooWapDaBug
Jan 18 at 22:16
1
1
as an auto-correct you might check en.cppreference.com/w/cpp/algorithm/next_permutation
â papagaga
Jan 18 at 23:21
as an auto-correct you might check en.cppreference.com/w/cpp/algorithm/next_permutation
â papagaga
Jan 18 at 23:21
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
Headers and namespaces
We don't use <vector>, but do need <string>.
Bringing all names in from a namespace is problematic; namespace std particularly so. It can silently change the meaning of your program when you're not expecting it. Get used to using the namespace prefix (std is intentionally very short), or importing just the names you need into the smallest reasonable scope.
Bug
This loop fails when w is the empty string:
for (auto rit = next(w.rbegin()); rit!=w.rend(); ++rit) {
This can be fixed with an early return:
if (w.empty())
return w;
Algorithm
There's a standard algorithm called std::next_permutation() that does most of what we need. The one difference is that if its input is already the last permutation, it will wrap around to the first one and indicate (by its return value) that it has done so. We can use that to return the original input string in that case.
Tests
You've included no tests. I think we need to test the trivial case (empty string) and at least one case where we must return a new string and one where we already have the last possible permutation.
Improved code
#include <algorithm>
#include <string>
std::string closest_greater_lexicographical_permutation(const std::string& input)
auto word = input;
return std::next_permutation(word.begin(), word.end())
? word // we changed it
: input; // no change - already the last permutation
// Test program
#include <iostream>
static bool test(const std::string& input, const std::string& expected)
auto const actual = closest_greater_lexicographical_permutation(input);
if (actual == expected)
return 0;
std::cerr << "FAIL ("" << input << ""): "
"got "" << actual << "" "
"instead of "" << expected << """ << std::endl;
return 1;
int main()
return 0
+ test("", "")
+ test("aabb", "abab")
+ test("cba", "cba")
;
Oh, I like that way of running the tests, I hadn't seen it before. Thank you!
â WooWapDaBug
Jan 19 at 12:10
It's quick and dirty compared to a full-blown unit-test framework - just enough to do the job and no more. But I'm glad you like it!
â Toby Speight
Jan 19 at 13:01
Completely off topic but, which unit-test framework do you recommend? In my job they do something that I don't know if it makes any sense, they program the software in c++ and the the unit test in java with Junit test. Is there good frameworks for c++ in c++?
â WooWapDaBug
Jan 19 at 13:08
1
I don't have a recommendation, as I don't have wide enough experience. I've used QTest for my Qt code, and GTest for other C++, but only enough to be able to say that they both work.
â Toby Speight
Jan 19 at 13:15
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
Headers and namespaces
We don't use <vector>, but do need <string>.
Bringing all names in from a namespace is problematic; namespace std particularly so. It can silently change the meaning of your program when you're not expecting it. Get used to using the namespace prefix (std is intentionally very short), or importing just the names you need into the smallest reasonable scope.
Bug
This loop fails when w is the empty string:
for (auto rit = next(w.rbegin()); rit!=w.rend(); ++rit) {
This can be fixed with an early return:
if (w.empty())
return w;
Algorithm
There's a standard algorithm called std::next_permutation() that does most of what we need. The one difference is that if its input is already the last permutation, it will wrap around to the first one and indicate (by its return value) that it has done so. We can use that to return the original input string in that case.
Tests
You've included no tests. I think we need to test the trivial case (empty string) and at least one case where we must return a new string and one where we already have the last possible permutation.
Improved code
#include <algorithm>
#include <string>
std::string closest_greater_lexicographical_permutation(const std::string& input)
auto word = input;
return std::next_permutation(word.begin(), word.end())
? word // we changed it
: input; // no change - already the last permutation
// Test program
#include <iostream>
static bool test(const std::string& input, const std::string& expected)
auto const actual = closest_greater_lexicographical_permutation(input);
if (actual == expected)
return 0;
std::cerr << "FAIL ("" << input << ""): "
"got "" << actual << "" "
"instead of "" << expected << """ << std::endl;
return 1;
int main()
return 0
+ test("", "")
+ test("aabb", "abab")
+ test("cba", "cba")
;
Oh, I like that way of running the tests, I hadn't seen it before. Thank you!
â WooWapDaBug
Jan 19 at 12:10
It's quick and dirty compared to a full-blown unit-test framework - just enough to do the job and no more. But I'm glad you like it!
â Toby Speight
Jan 19 at 13:01
Completely off topic but, which unit-test framework do you recommend? In my job they do something that I don't know if it makes any sense, they program the software in c++ and the the unit test in java with Junit test. Is there good frameworks for c++ in c++?
â WooWapDaBug
Jan 19 at 13:08
1
I don't have a recommendation, as I don't have wide enough experience. I've used QTest for my Qt code, and GTest for other C++, but only enough to be able to say that they both work.
â Toby Speight
Jan 19 at 13:15
add a comment |Â
up vote
1
down vote
accepted
Headers and namespaces
We don't use <vector>, but do need <string>.
Bringing all names in from a namespace is problematic; namespace std particularly so. It can silently change the meaning of your program when you're not expecting it. Get used to using the namespace prefix (std is intentionally very short), or importing just the names you need into the smallest reasonable scope.
Bug
This loop fails when w is the empty string:
for (auto rit = next(w.rbegin()); rit!=w.rend(); ++rit) {
This can be fixed with an early return:
if (w.empty())
return w;
Algorithm
There's a standard algorithm called std::next_permutation() that does most of what we need. The one difference is that if its input is already the last permutation, it will wrap around to the first one and indicate (by its return value) that it has done so. We can use that to return the original input string in that case.
Tests
You've included no tests. I think we need to test the trivial case (empty string) and at least one case where we must return a new string and one where we already have the last possible permutation.
Improved code
#include <algorithm>
#include <string>
std::string closest_greater_lexicographical_permutation(const std::string& input)
auto word = input;
return std::next_permutation(word.begin(), word.end())
? word // we changed it
: input; // no change - already the last permutation
// Test program
#include <iostream>
static bool test(const std::string& input, const std::string& expected)
auto const actual = closest_greater_lexicographical_permutation(input);
if (actual == expected)
return 0;
std::cerr << "FAIL ("" << input << ""): "
"got "" << actual << "" "
"instead of "" << expected << """ << std::endl;
return 1;
int main()
return 0
+ test("", "")
+ test("aabb", "abab")
+ test("cba", "cba")
;
Oh, I like that way of running the tests, I hadn't seen it before. Thank you!
â WooWapDaBug
Jan 19 at 12:10
It's quick and dirty compared to a full-blown unit-test framework - just enough to do the job and no more. But I'm glad you like it!
â Toby Speight
Jan 19 at 13:01
Completely off topic but, which unit-test framework do you recommend? In my job they do something that I don't know if it makes any sense, they program the software in c++ and the the unit test in java with Junit test. Is there good frameworks for c++ in c++?
â WooWapDaBug
Jan 19 at 13:08
1
I don't have a recommendation, as I don't have wide enough experience. I've used QTest for my Qt code, and GTest for other C++, but only enough to be able to say that they both work.
â Toby Speight
Jan 19 at 13:15
add a comment |Â
up vote
1
down vote
accepted
up vote
1
down vote
accepted
Headers and namespaces
We don't use <vector>, but do need <string>.
Bringing all names in from a namespace is problematic; namespace std particularly so. It can silently change the meaning of your program when you're not expecting it. Get used to using the namespace prefix (std is intentionally very short), or importing just the names you need into the smallest reasonable scope.
Bug
This loop fails when w is the empty string:
for (auto rit = next(w.rbegin()); rit!=w.rend(); ++rit) {
This can be fixed with an early return:
if (w.empty())
return w;
Algorithm
There's a standard algorithm called std::next_permutation() that does most of what we need. The one difference is that if its input is already the last permutation, it will wrap around to the first one and indicate (by its return value) that it has done so. We can use that to return the original input string in that case.
Tests
You've included no tests. I think we need to test the trivial case (empty string) and at least one case where we must return a new string and one where we already have the last possible permutation.
Improved code
#include <algorithm>
#include <string>
std::string closest_greater_lexicographical_permutation(const std::string& input)
auto word = input;
return std::next_permutation(word.begin(), word.end())
? word // we changed it
: input; // no change - already the last permutation
// Test program
#include <iostream>
static bool test(const std::string& input, const std::string& expected)
auto const actual = closest_greater_lexicographical_permutation(input);
if (actual == expected)
return 0;
std::cerr << "FAIL ("" << input << ""): "
"got "" << actual << "" "
"instead of "" << expected << """ << std::endl;
return 1;
int main()
return 0
+ test("", "")
+ test("aabb", "abab")
+ test("cba", "cba")
;
Headers and namespaces
We don't use <vector>, but do need <string>.
Bringing all names in from a namespace is problematic; namespace std particularly so. It can silently change the meaning of your program when you're not expecting it. Get used to using the namespace prefix (std is intentionally very short), or importing just the names you need into the smallest reasonable scope.
Bug
This loop fails when w is the empty string:
for (auto rit = next(w.rbegin()); rit!=w.rend(); ++rit) {
This can be fixed with an early return:
if (w.empty())
return w;
Algorithm
There's a standard algorithm called std::next_permutation() that does most of what we need. The one difference is that if its input is already the last permutation, it will wrap around to the first one and indicate (by its return value) that it has done so. We can use that to return the original input string in that case.
Tests
You've included no tests. I think we need to test the trivial case (empty string) and at least one case where we must return a new string and one where we already have the last possible permutation.
Improved code
#include <algorithm>
#include <string>
std::string closest_greater_lexicographical_permutation(const std::string& input)
auto word = input;
return std::next_permutation(word.begin(), word.end())
? word // we changed it
: input; // no change - already the last permutation
// Test program
#include <iostream>
static bool test(const std::string& input, const std::string& expected)
auto const actual = closest_greater_lexicographical_permutation(input);
if (actual == expected)
return 0;
std::cerr << "FAIL ("" << input << ""): "
"got "" << actual << "" "
"instead of "" << expected << """ << std::endl;
return 1;
int main()
return 0
+ test("", "")
+ test("aabb", "abab")
+ test("cba", "cba")
;
answered Jan 19 at 10:25
Toby Speight
17.8k13491
17.8k13491
Oh, I like that way of running the tests, I hadn't seen it before. Thank you!
â WooWapDaBug
Jan 19 at 12:10
It's quick and dirty compared to a full-blown unit-test framework - just enough to do the job and no more. But I'm glad you like it!
â Toby Speight
Jan 19 at 13:01
Completely off topic but, which unit-test framework do you recommend? In my job they do something that I don't know if it makes any sense, they program the software in c++ and the the unit test in java with Junit test. Is there good frameworks for c++ in c++?
â WooWapDaBug
Jan 19 at 13:08
1
I don't have a recommendation, as I don't have wide enough experience. I've used QTest for my Qt code, and GTest for other C++, but only enough to be able to say that they both work.
â Toby Speight
Jan 19 at 13:15
add a comment |Â
Oh, I like that way of running the tests, I hadn't seen it before. Thank you!
â WooWapDaBug
Jan 19 at 12:10
It's quick and dirty compared to a full-blown unit-test framework - just enough to do the job and no more. But I'm glad you like it!
â Toby Speight
Jan 19 at 13:01
Completely off topic but, which unit-test framework do you recommend? In my job they do something that I don't know if it makes any sense, they program the software in c++ and the the unit test in java with Junit test. Is there good frameworks for c++ in c++?
â WooWapDaBug
Jan 19 at 13:08
1
I don't have a recommendation, as I don't have wide enough experience. I've used QTest for my Qt code, and GTest for other C++, but only enough to be able to say that they both work.
â Toby Speight
Jan 19 at 13:15
Oh, I like that way of running the tests, I hadn't seen it before. Thank you!
â WooWapDaBug
Jan 19 at 12:10
Oh, I like that way of running the tests, I hadn't seen it before. Thank you!
â WooWapDaBug
Jan 19 at 12:10
It's quick and dirty compared to a full-blown unit-test framework - just enough to do the job and no more. But I'm glad you like it!
â Toby Speight
Jan 19 at 13:01
It's quick and dirty compared to a full-blown unit-test framework - just enough to do the job and no more. But I'm glad you like it!
â Toby Speight
Jan 19 at 13:01
Completely off topic but, which unit-test framework do you recommend? In my job they do something that I don't know if it makes any sense, they program the software in c++ and the the unit test in java with Junit test. Is there good frameworks for c++ in c++?
â WooWapDaBug
Jan 19 at 13:08
Completely off topic but, which unit-test framework do you recommend? In my job they do something that I don't know if it makes any sense, they program the software in c++ and the the unit test in java with Junit test. Is there good frameworks for c++ in c++?
â WooWapDaBug
Jan 19 at 13:08
1
1
I don't have a recommendation, as I don't have wide enough experience. I've used QTest for my Qt code, and GTest for other C++, but only enough to be able to say that they both work.
â Toby Speight
Jan 19 at 13:15
I don't have a recommendation, as I don't have wide enough experience. I've used QTest for my Qt code, and GTest for other C++, but only enough to be able to say that they both work.
â Toby Speight
Jan 19 at 13:15
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185403%2fclosest-greater-lexicographical-permutation%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
Are you intentionally eschewing
std::next_permutation()? If so, consider marking this with reinventing-the-wheel.â Toby Speight
Jan 18 at 18:59
Oh, and what's it supposed to do if there is no valid result?
â Toby Speight
Jan 18 at 19:02
If there is no valid result it just returns the same string @TobySpeight
â WooWapDaBug
Jan 18 at 22:14
@TobySpeight Oh, i didn't know that existed, thank you for pointing it out!
â WooWapDaBug
Jan 18 at 22:16
1
as an auto-correct you might check en.cppreference.com/w/cpp/algorithm/next_permutation
â papagaga
Jan 18 at 23:21