[英]Algorithm to generating all permutations of a string with no adjacent characters
假設我有ABCDEF
。 然后,有6個! 重新排列該字符串的排列。 現在,我只想處理沒有相鄰字符的排列。 這意味着,我想看看滿足這些約束的所有排列:
我對這種算法的處理方法是以下偽代碼:
//generate all 6! permutations
//check all permutations and see where B is next to A || C
//remove all instances
//check all permutations and see where C is next to D
//remove all instances
//check all permutations and see where D is next to E
//remove all instances
//check all permutations and see where E is next to F
//remove all instances
但是,這些屏蔽操作變得非常低效,並且花費了我太多的時間,尤其是在我的字符串長度大於6的情況下。我如何才能更有效地做到這一點? 我看到這些類似的帖子, 1 , 2 ,並希望提取一些關鍵概念,可以幫助我。 但是,這也是蠻力檢查。 我實際上想從一開始就只生成唯一的模式,而不必生成所有內容並一一檢查。
編輯:當前這是我用來生成所有排列的內容。
static String[] designs;
static int index;
protected static String[] generateDesigns(int lengthOfSequence, int numOfPermutations){
designs = new String[numOfPermutations];
StringBuilder str = new StringBuilder("1");
for(int i = 2; i <= lengthOfSequence; i++)
str.append(i);
genDesigns("", str.toString()); //genDesigns(6) = 123456 will be the unique characters
return designs;
}
//generate all permutations for lenOfSequence characters
protected static void genDesigns(String prefix, String data){
int n = data.length();
if (n == 0) designs[index++] = prefix;
else {
for (int i = 0; i < n; i++)
genDesigns(prefix + data.charAt(i), data.substring(0, i) + data.substring(i+1, n));
}
}
算法的典型O(n!)
偽代碼,用於生成長度為n
的字符串的所有置換:
function permute(String s, int left, int right)
{
if (left == right)
print s
else
{
for (int i = left; i <= right; i++)
{
swap(s[left], s[i]);
permute(s, left + 1, right);
swap(s[left], s[i]); // backtrack
}
}
}
字符串ABC
的相應遞歸樹看起來像[從互聯網上拍攝的圖像]:
在交換之前,請檢查是否可以交換滿足給定約束的內容(檢查s[left]
和s[i]
新上一個和下一個新字符)。 這也將切斷遞歸樹的許多分支。
這是一個相當簡單的回溯解決方案,可在向排列中添加相鄰字符之前修剪搜索。
public class PermutationsNoAdjacent {
private char[] inputChars;
private boolean[] inputUsed;
private char[] outputChars;
private List<String> permutations = new ArrayList<>();
public PermutationsNoAdjacent(String inputString) {
inputChars = inputString.toCharArray();
inputUsed = new boolean[inputString.length()];
outputChars = new char[inputString.length()];
}
private String[] generatePermutations() {
tryFirst();
return permutations.toArray(new String[permutations.size()]);
}
private void tryFirst() {
for (int inputIndex = 0; inputIndex < inputChars.length; inputIndex++) {
assert !inputUsed[inputIndex] : inputIndex;
outputChars[0] = inputChars[inputIndex];
inputUsed[inputIndex] = true;
tryNext(inputIndex, 1);
inputUsed[inputIndex] = false;
}
}
private void tryNext(int previousInputIndex, int outputIndex) {
if (outputIndex == outputChars.length) { // done
permutations.add(new String(outputChars));
} else {
// avoid previousInputIndex and adjecent indices
for (int inputIndex = 0; inputIndex < previousInputIndex - 1; inputIndex++) {
if (!inputUsed[inputIndex]) {
outputChars[outputIndex] = inputChars[inputIndex];
inputUsed[inputIndex] = true;
tryNext(inputIndex, outputIndex + 1);
inputUsed[inputIndex] = false;
}
}
for (int inputIndex = previousInputIndex + 2; inputIndex < inputChars.length; inputIndex++) {
if (!inputUsed[inputIndex]) {
outputChars[outputIndex] = inputChars[inputIndex];
inputUsed[inputIndex] = true;
tryNext(inputIndex, outputIndex + 1);
inputUsed[inputIndex] = false;
}
}
}
}
public static void main(String... args) {
String[] permutations = new PermutationsNoAdjacent("ABCDEF").generatePermutations();
for (String permutation : permutations) {
System.out.println(permutation);
}
}
}
它打印ABCDEF的90個排列。 我只引用開頭和結尾:
ACEBDF
ACEBFD
ACFDBE
ADBECF
…
FDBEAC
FDBECA
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.