查找字符串的所有排列可以使用著名的Steinhaus-Johnson-Trotter算法。但如果字符串包含重复字符,例如
AABB,
那么可能的唯一组合将是4!/(2! * 2!)= 6
一种实现方法是我们可以将其存储在数组中,然后删除重复项。
是否有更简单的方法修改Johnson算法,以便我们永远不会生成重复的排列(以最有效的方式)?
查找字符串的所有排列可以使用著名的Steinhaus-Johnson-Trotter算法。但如果字符串包含重复字符,例如
AABB,
那么可能的唯一组合将是4!/(2! * 2!)= 6
一种实现方法是我们可以将其存储在数组中,然后删除重复项。
是否有更简单的方法修改Johnson算法,以便我们永远不会生成重复的排列(以最有效的方式)?
使用以下递归算法:
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;
}
正如您所看到的,这非常容易。
首先将字符串转换为一组唯一字符和它们出现的次数,例如BANANA -> (3, A), (1, B), (2, N)。这可以通过对字符串进行排序并分组字母来完成。然后,对于集合中的每个字母,在该字母少一个的所有排列前加上该字母(注意递归)。继续使用“BANANA”示例,我们有:permutations((3,A),(1,B),(2,N)) = A:(permutations((2,A),(1,B),(2,N)) ++ B:(permutations((3,A),(2,N)) ++ N:(permutations((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))
#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;
}
func
和calc
的函数,以及名为arr
、pref
、pos
、adr
、p
、l
、i
、z
、p
、s
和str
的变量;它们的用途都不明显。使用更具描述性的变量名称将极大地提高代码的可读性。 - BlueRaja - Danny Pflughoeftz
应该是 bool
,#include <stdbool.h>
);不要使用魔法数字(arr
的大小,p
的大小);永远不要使用 strcpy()
;别忘了在 malloc()
上调用 free()
:) - BlueRaja - Danny Pflughoeftimport 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));
}
}
}
}