简体   繁体   中英

How to generate only so many permutations more efficiently in C++?

I'm trying to solve a problem and I feel like I'm really close to it but it's still a little slow because I'm generating so many permutations.

I need the permutations of "0123456789". I know there are (10)! permutations which is a lot. I use an std::unordered_set because I don't care about the order they are stored in and it seemed faster than using a regular std::set

Here is some core I wrote: max_perm_size is the size of the string of permutations I care about for a particular case.

void getPermutations(unordered_set<string> &permutations, int &max_perm_size)
{
    string digits = "0123456789";

    do{

        permutations.insert(digits.substr(0, max_perm_size));

    } while (next_permutation(digits.begin(), digits.end()));

}

I have two main questions about this code:

  1. Above I'm still generating then entire "0123456789" permutation even for cases where I only care about permutations of size max_perm_size . I just trim them afterwords before storing them into my std::unordered_set . Is there a way to do this in a better way so it's faster?
  2. For the worst case max_pem_size = 10 , is there a more efficient way for me to generate and store all of these permutations in general?

As far as a I can tell, your result is numbers (without repeated digits) from 0 through some limit. Since you say you don't care about the order of the digits, it's probably easiest if we just stick to ascending ones. That being the case, we can generate results like this:

#include <iostream>

int main() {
    for (int i=0; i<10; i++)
        for (int j=i+1; j<10; j++)
            for (int k=j+1; k<10; k++)
                std::cout << i << j << k << "\t";
}

Result:

012     013     014     015     016     017     018     019     023     024     025     026     027
028     029     034     035     036     037     038     039     045     046     047     048     049
056     057     058     059     067     068     069     078     079     089     123     124     125
126     127     128     129     134     135     136     137     138     139     145     146     147
148     149     156     157     158     159     167     168     169     178     179     189     234
235     236     237     238     239     245     246     247     248     249     256     257     258
259     267     268     269     278     279     289     345     346     347     348     349     356
357     358     359     367     368     369     378     379     389     456     457     458     459
467     468     469     478     479     489     567     568     569     578     579     589     678
679     689     789

If your limit isn't a number of digits, you can put the digits together into an actual int and compare (then break out of the loops).

This is specific to your case, not a general solution, but for the case of digit permutations, you can do:

void getPermutations(unordered_set<string> &permutations, int max_perm_size)
{
    if (max_perm_size < 1) return;

    uint64_t stopat = 1;
    for (int i = 1; i < max_perm_size; ++i) {
        stopat *= 10;
    }

    for (uint64_t dig = 0; dig < stopat; ++dig) {
        std::ostringstream ss;
        ss << std::setw(max_perm_size) << std::setfill('0') << dig;
        permutations.insert(ss.str());
    }
}
  1. You can take a substring of your digits string first. Then your loop will only deal with permutations of max_perm_size.

  2. You could create a class that generates permutations on demand instead of pre-generating and storing them beforehand. Depending on your application, you may not even have to store them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM