如何获得两个字符串的所有排列组合?

时间:2014-01-31 08:49:05

标签: c++ string algorithm

我有两个单词,我希望获得这些单词组合的所有排列。必须保留每个字符串中字符的相对顺序

看看这个例子:

Input= "abc", "mn"

Output= "abcmn", "abmnc", "amnbc", "mnabc", "mabcn", "manbc", "mabnc", "ambnc", "ambcn", "abmcn"

我搜索stackoverflow.com,并获得以下代码,但它不起作用!

void print_towstring(const std::vector<int>& v, const std::string& s1, const std::string& s2)
{
    std::size_t i1 = 0;
    std::size_t i2 = 0;

    for (int i : v) {
        std::cout << ((i == 0) ? s1[i1++] : s2[i2++]);
    }
    std::cout << std::endl;
}

void towstring(const std::string& s1, const std::string& s2)
{
    std::vector<int> v(s1.size(), 0);

    v.insert(v.end(), s2.size(), 1);
    do
    {
        print_towstring(v, s1, s2);
    } while (std::next_permutation(v.begin(), v.end()));
}

int main(int argc, char *argv[])
{
    towstring("abc", "mn");
    return 0;
}

如何在c ++中编写排列组合算法?

4 个答案:

答案 0 :(得分:2)

我认为你可以递归地做到这一点。基本上在每一步你创建两个分支:一个在你的字符串中添加一个字母,从右边的字符串,另一个分支,你从左边的字符串添加第一个字母:

    void AddNext(
      std::string const& left,
      std::string const& right,
      std::string const& current,
      std::vector< std::string >& results)
    {
      if (left.empty())
      {
        current.append(right);
        results.push_back(current);
        return;
      }
      else if (right.empty())
      {
         current.append(left);
         results.push_back(current)
         return;
      }
      else
      {
        AddNext(left, right.substr(1, right.size() -1), current + std::string(1, right[0]), results);
        AddNext(left.substr(1, left.size() -1), right, current + std::string(1, left[0]), results);
      }
}

答案 1 :(得分:2)

似乎你可以通过0和1的序列来表示“置换组合”,其中每个数字告诉从下一个字符采用哪个字符串,如下所示:

00101 - means abmcn

因此,您现在必须生成所有这样的字符串,这些字符串具有给定数量的0和给定数量的1(在您的示例中为3和2)。要做到这一点,我想,最简单的方法是迭代0和1的所有组合,扔掉那些没有所需数量1的组合。

我喜欢用最低有效位开始用数字表示一串位,例如00101对应

0 * 2^0 +
0 * 2^1 +
1 * 2^2 +
0 * 2^3 +
1 * 2^4 = 20

(警告:这只适用于有限的字符串大小 - 最多32位 - 或任何位数int。对于更长的字符串,实现可以适应64位,但它不值得,因为无论如何它会太慢了)

从这样的数字中得到一个给定的位:

int GetBit(int n, int b)
{
    return (n >> b) & 1;
}

将此数字转换为矢量:

void ConvertNumberToVector(int n, std::vector<int>& v)
{
    for (int b = 0; b < v.size(); ++b)
        v[b] = GetBit(n, b);
}

然后,您可以将此向量与print_towstring函数一起使用。

答案 2 :(得分:2)

(我的)代码有效:http://ideone.com/IYYVZY

它只使用C ++ 11。 对于C ++ 03,请参阅http://ideone.com/ZHXSkt

您必须更改for range loop

for (int e : v) - &gt; for (std::size_t i = 0, size = v.size(); i != size; ++i) { int e = v[i]; ..

答案 3 :(得分:1)

我将基于 anatolyg 的方法,为n输入字符串提供解决方案,为简单起见{... 1 (看我要去哪里?)。注意一个字符串的相对排序永远不会改变?这是算法的基础

第1步: 你把你的字符串放在一个数组或向量或其他什么。对于每个字符串,您指定一个大小为1的符号,如第一个符号n <=10,第二个符号0,直到1

steps2:你有一个函数可以将输入转换为单个字符串(或更好的向量),其中每个字符都来自原始字符串。在您的情况下,函数是:

9

steps3:您枚举结果字符串的排列,在本例中为“00011”。您已使用 f("abc", "mn") => "00011"

走在正确的轨道上

steps4:迭代每个结果字符串并使用其符号作为掩码。

之类的东西
std::next_permutation()

所以

void mergewithmask(std::string& target, std::string& input, char mask )
{
 int i = 0;//target index
 int j = 0;//input index
 for(i = 0; i < target.size(); i++)
 {
   if(target[i] == mask){
      target[i] = input[j];
      j++;
   }
 }
}

为了使这种方法起作用,您需要使用不会与初始输入发生冲突的符号。例如,使用负数向量将保证不会与char数组和无限量的输入字符串发生冲突......