字符串排列:如何去除重复排列
Permutation of String letters: How to remove repeated permutations?
这里有一个标准函数来打印字符串的字符排列:
void permute(char *a, int i, int n)
{
int j;
if (i == n)
printf("%sn", a);
else
{
for (j = i; j < n; j++) //check till end of string
{
swap((a+i), (a+j));
permute(a, i+1, n);
swap((a+i), (a+j)); //backtrack
}
}
}
void swap (char *x, char *y)
{
char temp;
temp = *x;
*x = *y;
*y = temp;
}
它工作得很好,但有一个问题,它还打印一些重复的排列,例如:
如果字符串是"AAB">
输出为:
AAB
ABA
AAB
ABA
BAA
BAA
这也有3个重复条目。
有没有办法防止这种情况发生?
--
感谢
Alok Kr.
记下之前交换过的字符:
char was[256];
/*
for(j = 0; j <= 255; j++)
was[j] = 0;
*/
bzero(was, 256);
for (j = i; j <= n; j++)
{
if (!was[*(a+j)]) {
swap((a+i), (a+j));
permute(a, i+1, n);
swap((a+i), (a+j)); //backtrack
was[*(a+j)] = 1;
}
}
这一定是迄今为止参赛作品中速度最快的一个,是"AAAABBBCCD"(100个循环(上的一些基准:
native C - real 0m0.547s
STL next_permutation - real 0m2.141s
标准库有您需要的:
#include <algorithm>
#include <iostream>
#include <ostream>
#include <string>
using namespace std;
void print_all_permutations(const string& s)
{
string s1 = s;
sort(s1.begin(), s1.end());
do {
cout << s1 << endl;
} while (next_permutation(s1.begin(), s1.end()));
}
int main()
{
print_all_permutations("AAB");
}
结果:
$ ./a.out
AAB
ABA
BAA
另一种方法可能是:
-
对阵列进行预排序。
-
这将确保所有重复现在都是连续的。
-
所以,我们只需要看到我们修复(并排列其他(的前一个元素
-
若当前元素和前一个元素相同,则不要置换。
我会按照以下方式进行:首先,我生成字符的"组"(即AABBBC
产生两个组:(AA) and (BBB) and (C)
。
首先,我们将AA
的所有分布迭代到n
字符上。对于找到的每个分布,我们在BBB
的所有分布上迭代到n-2
的剩余字符(未被A
占用(。对于涉及A
s和B
s的这些分布中的每一个,我们将C
的所有分布迭代到剩余的自由字符位置上。
您可以使用std::set
来确保结果的唯一性。如果它是C++的话(因为你把它标记为C++(。
否则-手动浏览结果列表并删除重复项。
当然,你必须保存结果并进行后处理,而不是像现在这样立即打印。
如果您只是认为这是一个需要存储所有排列以备将来使用的问题,那么这将非常简单。
所以你会有一个排列字符串的数组。
现在考虑一个新问题,它也是一个标准问题,需要从数组中删除重复项。
我希望这能有所帮助。
@Kumar,我认为你想要的是以下内容:
#include <stdio.h>
#include <string.h>
/* print all unique permutations of some text. */
void permute(int offset, int* offsets, const char* text, int text_size)
{
int i;
if (offset < text_size) {
char c;
int j;
/* iterate over all possible digit offsets. */
for (i=0; i < text_size; i++) {
c=text[i];
/* ignore if an offset further left points to our
location or to the right, with an identical digit.
This avoids duplicates. */
for (j=0; j < offset; j++) {
if ((offsets[j] >= i) &&
(text[offsets[j]] == c)) {
break;
}
}
/* nothing found. */
if (j == offset) {
/* remember current offset. */
offsets[offset]=i;
/* permute remaining text. */
permute(offset+1, offsets, text, text_size);
}
}
} else {
/* print current permutation. */
for (i=0; i < text_size; i++) {
fputc(text[offsets[i]], stdout);
}
fputc('n', stdout);
}
}
int main(int argc, char* argv[])
{
int i, offsets[1024];
/* print permutations of all arguments. */
for (i=1; i < argc; i++) {
permute(0, offsets, argv[i], strlen(argv[i]));
}
return 0;
}
这段代码是C,按照要求,它非常快,可以做你想做的事。当然,它包含了一个可能的缓冲区溢出,因为偏移缓冲区有一个固定的大小,但这只是一个例子,对吧?
编辑:有人试过这个吗?有没有更简单或更快的解决方案?令人失望的是再也没有人评论了!
void permute(string set, string prefix = ""){
if(set.length() == 1){
cout<<"n"<<prefix<<set;
}
else{
for(int i=0; i<set.length(); i++){
string new_prefix = prefix;
new_prefix.append(&set[i], 1);
string new_set = set;
new_set.erase(i, 1);
permute(new_set, new_prefix);
}
}
}
并简单地将其用作permute("单词"(;
不要在string
的不同位置对同一个字符进行排列。
在Python中:
def unique_permutation(a, l, r):
if l == r:
print ''.join(a)
return
for i in range(l, r+1):
if i != l and a[i] == a[l]:
continue
a[i], a[l] = a[l], a[i]
unique_permutation(a, l+1, r)
a[i], a[l] = a[l], a[i]
算法步骤:
- 将给定字符串存储到临时字符串中,比如"temp">
- 从临时字符串中删除重复项
- 最后调用"void permute(char*a,int i,int n("函数,打印给定字符串的所有排列,不重复
我认为,这是最好和有效的解决方案。
- 找到具有最多子串栅栏的字符串排列
- 为什么我得到长度仅为 3 的字符串排列的输出?
- 如何排列二进制字符串以最小化它们之间的距离
- C++按字母顺序排列的字符串数组
- 有没有一种 STL 方法可以找到字符串的所有排列,给出一个以 C++ 为单位的大小?
- 如何在 c++ 中按字母顺序排列数组中的字符串?
- 在c++中生成字符串的排列
- 从给定字符串中查找长度 k 的所有排列/组合
- C++ 字符串的排列,输出的结果小于或等于字符串的长度
- 生成具有条件的给定字符串的排列
- 从左到右打印字符串的组合(不是排列)c++
- 如何找到通过仅移动相邻字符创建的字符串的排列?-C++
- 如何在C++中分隔和排列名字和全名字符串
- 如何从长度为 n 的字符串中获取 lengh k 的所有唯一排列的数量
- 它如何排列单词以使用 qsort 和字符串
- 如何按大小写顺序排列字符串(而不是按字典顺序排列)
- 如何用数字排列字符串
- 按字母顺序排列字符串数组(甚至是*ptr)
- 使用swap按字母顺序排列字符串数组
- 为什么 std::sort 不按字母顺序排列字符串数组?