3
\$\begingroup\$

I've been preparing for interviews and picking up modern C++. A recent prep question I did was to find all combinations (or distinct subsets) of letters from a string. E.g. 'AA2'-> {'A', '2', 'A2', 'AA2'}. Note that the order doesn't matter. I would like feedback both on the approach and on use of C++ style/best practices. My attempt is:

#include <string>
#include <algorithm>
#include <unordered_set>
#include <iostream>
std::unordered_set<std::string> getPermutations(std::string str){
 std::unordered_set<std::string> ret;
 if (str.length() <= 1){
 ret.insert(str);
 } else {
 char removedLetter = '0円';
 for(unsigned i = 0; i < str.length(); i++){
 if (removedLetter == str[i]){ //Already found all subsets missing this character
 continue;
 }
 removedLetter = str[i];
 std::string subString = str.substr(0, i) + str.substr(i+1, std::string::npos);
 std::unordered_set<std::string> shorter = getPermutations(subString);
 for(auto shortPerm : shorter){
 ret.insert(shortPerm);
 auto ind = shortPerm.begin();
 for(; ind < shortPerm.end(); ind++){ //Find where to insert letter so that ordering is preserved for eliminating duplicates
 if(*ind > removedLetter){
 break;
 }
 }
 shortPerm.insert(ind, removedLetter);
 ret.insert(shortPerm);
 }
 }
 }
 return ret;
}
int main(int argc, char ** argv){
 std::string str;
 std::cin >> str;
 std::sort(str.begin(), str.end()); //Sort string so that method works.
 for(const auto &p : getPermutations(str)){
 std::cout << p << ' ';
 }
 std::cout << std::endl;
}
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Jun 5, 2016 at 18:19
\$\endgroup\$
2
  • \$\begingroup\$ In the example, the empty combination is omitted. Is this on pourpose? \$\endgroup\$ Commented Jun 5, 2016 at 18:29
  • \$\begingroup\$ Yes, no empty combination, and input is at least one character \$\endgroup\$ Commented Jun 5, 2016 at 18:34

1 Answer 1

3
\$\begingroup\$

Minor remarks

  • Since the sortedness of the input is a precondition of getPermutations, I would either do this step in the function itself, or at least add a check for this condition.
  • Passing string by reference instead of by value: I recommend passing const std::string & instead of std::string. In this way, the string does not get copied to the stack. This matters especially, if the string is very long.

Alternative

While the recursive approach is elegant and easily understandable, it might be less convenient for very long inputs. I suggest another solution, based on the idea, that if you want all permutations, then each character can either be part, or not be part of a permutation. This gives us 2^N possible permutations, where N is the length of the input. So, you can just generate this number (2^N), and then iterate from 0 to 2^N-1, and calculate the corresponding perm. for each number. So, if the number is represented as binary digits, then 1 means that the character at the corresponding position should be part of the permutation, 0 that it should not. (If you do not need the empty perm., just start the iteration from 1, instead of 0.)

With your example, 'AA2', this would work as follows: N=3, so iterate from 0 to 7 (=2^3 - 1). 0 corresponds to the empty set. 1 = 001b, so '2' is part of the permutation. 2 = 010b, so only (the second) 'A' is part of the permutation. 3 = 011b, so the perm. is A2, etc.

Remarks:

  • This approach would yield two identical 'A2' perms., but you can avoid that by storing the return value in a set, as you are currently doing it (unless you do want both).
  • With this solution, it is not needed to sort the input.
  • Other representations are possible as well, e.g a vector of booleans, instead of a number (especially convenient very large inputs).
answered Jun 5, 2016 at 18:58
\$\endgroup\$
1
  • \$\begingroup\$ Thanks! Good point about using const; I hadn't thought about an iterative solution b/c this question was in the recursion section, but that's a nice approach! \$\endgroup\$ Commented Jun 5, 2016 at 19:11

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.