获取所有没有重复的组合

Posted

技术标签:

【中文标题】获取所有没有重复的组合【英文标题】:Get all combinations without duplicates 【发布时间】:2018-09-03 06:52:02 【问题描述】:

在 c++ 中给出一个字符串的所有可能组合,不重复。 示例输入:“123”,输出组合为:

 1,12,123,13,2,23,3.

重复的示例是“12”=="21" 或“123”=="213"。

假设一个字符不会被多次使用。另外我不认为递归是强制性的。

这里有一个 php 答案。(Get all possible combinations without duplicates)。

我曾考虑过某种形式的结果树,但不确定如何使用递归实现。

我的答案包括重复如下:

#include <string>
#include <iostream>
using namespace std;

void get( string str, string res ) 

   cout << res << endl;

   for( int i = 0; i < str.length(); i++ )
      get( string(str).erase(i,1), res + str[i] );


int main( int argc, char **argv) 
   string str = "123";
   get( str, "" );
   return 0;

这是一个面试问题,没有重复的问题让我感到震惊。提前感谢您的帮助。

【问题讨论】:

你在找std::next_permutation吗? 输入是否不应该包含两次相同的字符? (例如“aab”,您是否认为这不会发生,您是否必须检测它并发出错误信号,您是否输出“a,b,ab,aa,aab”?) @JesperJuhl 我认为这不是他想要的。他不想要排列,他想要所有可能的字符串,可以通过从原始字符串中删除字母来获得。 @Caninonos,我认为假设同一个字符不会被使用两次更容易。 那么有这个有点幼稚的解决方案:ideone.com/m2UX2u 【参考方案1】:

OP 正在寻找的内容等同于 Power Set 减去 Empty Set。无需递归即可轻松实现所需的输出。这是一个简单的方法:

#include <vector>
#include <string>
#include <cmath>
#include <iostream>

void GetPowerSet(std::string v) 

    std::string emptyString;
    std::vector<std::string> powerSet;
    int n = (int) std::pow(2.0, (double) v.size()); // Get size of power set of v
    powerSet.reserve(n);
    powerSet.push_back(emptyString); // add empty set

    for (std::string::iterator it = v.begin(); it < v.end(); it++) 
        unsigned int tempSize = powerSet.size();
        for (std::size_t j = 0; j < tempSize; j++)
            powerSet.push_back(powerSet[j] + *it);
    

    // remove empty set element
    powerSet.erase(powerSet.begin());

    // print out results
    std::cout << "Here is your output : ";
    for (std::vector<std::string>::iterator it = powerSet.begin(); it < powerSet.end(); it++)
        std::cout << *it << ' ';


int main() 
    std::string myStr;
    std::cout << "Please enter a string : ";
    std::cin >> myStr;
    GetPowerSet(myStr);
    return 0;

这是输出:

Please enter a string : 123
Here is your output : 1 2 12 3 13 23 123

解释:

我们首先注意到幂集的大小由2^n 给出,其中n 是初始集的大小。出于我们的目的,我们的最终向量将仅包含 2^n - 1 元素,但是我们仍然需要保留 2^n 以防止调整大小,因为构建我们的结果需要 "empty" 元素。

真正的工作是在GetPowerSet中间的两个for loops里面进行的。我们从一个空白元素开始。然后我们遍历原始向量中的每个字符,一路创建我们的幂集的子集。 例如

    用空集初始化电源集:powerSet = v 的第一个元素添加到上述幂集的每个元素中:'' + '1' = '1'powerSet = , '1'v 的第二个元素添加到上述幂集的每个元素中:'' + '2' = '2', '1' + '2' = '12' powerSet = , '1', '2', '12'v 的第三个元素添加到上述幂集的每个元素中:'' + '3' = '3', '1' + '3' = '13', '2' + '3' = '23', '12' + '3' = '123' powerSet = , '1', '2', '12', '3', '13', '23', '123' 现在移除上述能量集中的第一个元素。 powerSet = '1', '2', '12', '3', '13', '23', '123'

我们完成了。

【讨论】:

非常感谢!几乎就像我试图达到但无法完全破解的二进制计数!【参考方案2】:

我想我会在 cmets 中添加来自 @Caninonos 的答案。我只是稍微简化了它,删除了模板等。这是一个递归解决方案。

#include <iostream>
#include <vector>
using namespace std;

void get_substrings_aux(vector<string>& subs, string str ,unsigned int cnt) 

    if(cnt == str.size())
    return;

    int n = subs.size();
    char c = str[cnt];
    for(int i = 0 ; i < n ; ++i) 
        subs.push_back(subs[i] + c);
        cout << subs[i] + c << endl;
    
    get_substrings_aux(subs, str, ++cnt);


vector<string> get_substrings(const string& str) 
    vector<string> subs(1);
    int cnt=0;
    get_substrings_aux(subs, str, cnt);
    subs.erase(subs.begin());
    return subs;


int main() 
    string str("1234");
    vector<string> subs = get_substrings(str);
    return 0;

【讨论】:

以上是关于获取所有没有重复的组合的主要内容,如果未能解决你的问题,请参考以下文章

获取R中的所有组合,允许重复

在不指定元素数量的情况下获得逻辑变量的所有可能组合[重复]

如何获取在 SQL 中具有重复列组合的记录? [复制]

从组合框的值中获取选项的文本[重复]

从python列表中获取元素的唯一组合[重复]

R中不重复的组合