我有两个单词,我希望获得这些单词组合的所有排列。必须保留每个字符串中字符的相对顺序
看看这个例子:
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 ++中编写排列组合算法?
答案 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数组和无限量的输入字符串发生冲突......