通过众所周知的Steinhaus-Johnson-Trotter算法找到字符串的所有排列。但是如果字符串包含重复的字符,例如
AABB,
然后可能的唯一组合将是4!/(2!* 2!)= 6
实现这一目标的一种方法是我们可以将它存储在数组中,然后删除重复数据。
是否有任何更简单的方法来修改Johnson算法,因此我们永远不会生成重复的排列。 (以最有效的方式)
答案 0 :(得分:5)
使用以下递归算法:
PermutList Permute(SymArray fullSymArray){
PermutList resultList=empty;
for( each symbol A in fullSymArray, but repeated ones take only once) {
PermutList lesserPermutList= Permute(fullSymArray without A)
for ( each SymArray item in lesserPermutList){
resultList.add("A"+item);
}
}
return resultList;
}
如你所见,这很容易
答案 1 :(得分:3)
我认为这个问题本质上是生成 multiset排列的问题。这篇论文似乎是相关的:J。F. Korsh P. S. LaFollette。无环阵列生成 multiset排列。 The Computer Journal,47(5):612-621,2004。
摘自:本文提出了一种无循环算法来生成多集的所有排列。每个都是通过进行一次换位从其前身获得的。它与以前的此类算法不同,它使用数组进行排列,但要求存储的长度只是线性的。
答案 2 :(得分:3)
首先将字符串转换为一组唯一字符和出现次数,例如香蕉 - > (3,A),(1,B),(2,N)。 (这可以通过排序字符串和分组字母来完成)。然后,对于集合中的每个字母,将该字母前置到集合的所有排列中,少一个字母(注意递归)。继续“BANANA”的例子,我们有:排列((3,A),(1,B),(2,N))= A :(排列((2,A),(1,B),(2) ,N))++ B :(置换((3,A),(2,N))++ N :(置换((3,A),(1,B),(1,N))
以下是Haskell中的一个有效实现:
circularPermutations::[a]->[[a]]
circularPermutations xs = helper [] xs []
where helper acc [] _ = acc
helper acc (x:xs) ys =
helper (((x:xs) ++ ys):acc) xs (ys ++ [x])
nrPermutations::[(Int, a)]->[[a]]
nrPermutations x | length x == 1 = [take (fst (head x)) (repeat (snd (head x)))]
nrPermutations xs = concat (map helper (circularPermutations xs))
where helper ((1,x):xs) = map ((:) x)(nrPermutations xs)
helper ((n,x):xs) = map ((:) x)(nrPermutations ((n - 1, x):xs))
答案 3 :(得分:1)
在我的解决方案中,我递归地生成选项,每次尝试添加我不需要使用的每个字母。
#include <string.h>
void fill(char ***adr,int *pos,char *pref) {
int i,z=1;
//loop on the chars, and check if should use them
for (i=0;i<256;i++)
if (pos[i]) {
int l=strlen(pref);
//add the char
pref[l]=i;
pos[i]--;
//call the recursion
fill(adr,pos,pref);
//delete the char
pref[l]=0;
pos[i]++;
z=0;
}
if (z) strcpy(*(*adr)++,pref);
}
void calc(char **arr,const char *str) {
int p[256]={0};
int l=strlen(str);
char temp[l+1];
for (;l>=0;l--) temp[l]=0;
while (*str) p[*str++]++;
fill(&arr,p,temp);
}
使用示例:
#include <stdio.h>
#include <string.h>
int main() {
char s[]="AABAF";
char *arr[20];
int i;
for (i=0;i<20;i++) arr[i]=malloc(sizeof(s));
calc(arr,s);
for (i=0;i<20;i++) printf("%d: %s\n",i,arr[i]);
return 0;
}
答案 4 :(得分:1)
这是一个棘手的问题,我们需要使用递归来查找字符串的所有排列,例如“AAB”排列将是“AAB”,“ABA”和“BAA”。 我们还需要使用设置来确保没有重复值。
import java.io.*;
import java.util.HashSet;
import java.util.*;
class Permutation {
static HashSet<String> set = new HashSet<String>();
public static void main (String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("Enter :");
StringBuilder str = new StringBuilder(in.nextLine());
NONDuplicatePermutation("",str.toString()); //WITHOUT DUPLICATE PERMUTATION OF STRING
System.out.println(set);
}
public static void NONDuplicatePermutation(String prefix,String str){
//It is nlogn
if(str.length()==0){
set.add(prefix);
}else{
for(int i=0;i<str.length();i++){
NONDuplicatePermutation(prefix+ str.charAt(i), str.substring(0,i)+str.substring(i+1));
}
}
}
}