Closest greater lexicographical permutation

The name of the pictureThe name of the pictureThe name of the pictureClash 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;







share|improve this question















  • 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
















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;







share|improve this question















  • 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












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;







share|improve this question











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;









share|improve this question










share|improve this question




share|improve this question









asked Jan 18 at 14:25









WooWapDaBug

348214




348214







  • 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












  • 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







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










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")
;






share|improve this answer





















  • 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










Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















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






























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")
;






share|improve this answer





















  • 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














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")
;






share|improve this answer





















  • 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












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")
;






share|improve this answer













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")
;







share|improve this answer













share|improve this answer



share|improve this answer











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
















  • 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












 

draft saved


draft discarded


























 


draft saved


draft discarded














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













































































Popular posts from this blog

Python Lists

Aion

JavaScript Array Iteration Methods