通过删除生成所有可能的排列

时间:2013-08-22 15:02:09

标签: java math guava permutation

我需要通过删除字符串的一个或多个BIG字符来生成所有可能的唯一排列,而小字符应保持不变。

示例输入:

AalAADBdBBDkCeCCA

现在我需要通过

生成所有可能的排列
  • 一次或多次删除一个BIG字符
  • 组合删除1到n个BIG字符,每个字符被删除0到m次(n =输入中直接字符数,m =字符出现次数)。
  • 留下小字符未触动

我只对独特的排列感兴趣,也就是说,如果第二个或第三个(FIXED!最初我写的第一个和第二个)A被删除没有区别。当然,如果删除第一个或最后一个A,它会产生影响。

排列示例:

AalAADBdBBDkCeCCA // original input also counts as permutation
AalAADBdBB kCeCCA // last D removed
 alAAD dBBDkCeCCA // first A and first B removed
Aal  D dBBDkCeC A  // second and third A removed, first B and last C removed

我正在使用番石榴,以防万一。一个普通的Java解决方案也没问题。

如果有这种排列的名称和一些数学公式给出唯一排列的总量,我也会感兴趣,因此可以验证排列算法结果(至少在正确的排列量方面)。

该示例是一个简化问题,可以假设输入已经可用作字符列表或其他任何预解析格式而不是合并字符串。

感谢您提供任何暗示!

更新

我想我找到了一个解决方案,欢迎反馈。 想法:提取每个BIG角色的索引(位置)。将它们放入一组,创建该组的功率组P.这给出了可能删除的所有排列(包括重复,例如1,2和2,1以及如果1 = 2 =相同的BIG字符)

1 个答案:

答案 0 :(得分:1)

我对你的更新有一些类似的想法,但也许你的结果会比我更优雅,因为我没有过滤任何东西

我首先创建了一个包含字符串中所有大写字母的二进制表(我们可以忽略小写,因为它们从未被触及)。

从非常简单的示例开始,一路向上。 在二进制表中,0表示将字符保留在原来的位置,1表示将其删除。

e.g。对于字符串A(或任何只有1个大写字母的字符串,例如aaaAa)2个排列

A
0
1

表示AB(或2个大写字母aaaAaBbb的字符串)4个排列

AB
00
10
01
11

用于ABC 8排列

ABC
000
100
010
110
001
101
011
111

用于ABCD 16排列

ABCD
0000
1000
0100
1100
0010
1010
0110
1110
0001
1001
0101
1101
0011
1011
0111
1111

你会看到这些是2 ^ 1,2 ^ 2,2 ^ 3,2 ^ 4 2 ^ numberOfUppercaseCharacters

这为您提供了总数排列,但没有删除重复项问题。 您可能会优雅地实现一种蛮力方法,该方法循环通过关闭字符的每个字符位置 - 并将输出字符串保存到一组。因为它在一组中不会添加重复项。

所以拿你的输入字符串  解析它以获取每个大写字符的索引

在上面的二进制表中,概念上考虑用字符串中的索引位置替换A B C.

所以

对于字符串aaAbbBb,我们有索引2和5(基于0的索引)

A B
_ _
0 0
1 0
0 1
1 1

变为

2 5
_ _
0 0
1 0
0 1
1 1

因此,如果我们将二进制数表示为2 ^ numOfUppercase并删除应该起作用的关联值。下面的示例示例包含字符串和大写索引列表硬编码。至少你有一些东西要尝试并检查你的解决方案。

注意不知道这种方法的上限 - 可能会因为长字符串大字符作为排列的大型二进制表示而落空。

此处的示例:

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;


public class StringProcessing {


public static void main(String[] args) {
    // TODO Auto-generated method stub
    StringProcessing sp = new StringProcessing();
    sp.setUpProcessing();

}

public void setUpProcessing() {
    String input = "aaABCDcs";

    //Populate with indexes of Uppercase letters (loop though each char and check if [A-Z])
    ArrayList<Integer> indexes = new ArrayList<Integer>();
    indexes.add(2);
    indexes.add(3);
    indexes.add(4);
    indexes.add(5);

    Set<String> permutationStore = new HashSet<String>();
    BigInteger permutations = BigInteger.valueOf(2).pow(indexes.size());  //2^numOfUppercaseChars


    int maxSize = getMaxLength(permutations); //Need this for padding binary with 0

    for (BigInteger index = BigInteger.ZERO; index.compareTo(permutations) < 0;  index = index.add(BigInteger.ONE)) {
        String binary = index.toString(2);
       // System.out.println(permutations + " " + index + " " + binary + ", for string: " + input); //NumOf Permutations, currentPermutation, binaryRepresentation

        int lastIndex = binary.length() -1;
        StringBuilder currentString = new StringBuilder(input);
        String permutationString = process(lastIndex, binary, currentString, indexes, maxSize);
        permutationStore.add(permutationString);
        System.out.println(permutations + " " + index + "    " + binary + ", for string: " + input + ", Stored: " + permutationString);
    }

    System.out.println("");
    for(String s : permutationStore) {
        System.out.println(s);
    }

}

public int getMaxLength(BigInteger permutations) {
   BigInteger zeroBased = permutations.subtract(BigInteger.ONE);
   return  zeroBased.toString(2).length();
}

public String process(int lastIndex, String binary, StringBuilder currentString, ArrayList<Integer> indexes, int maxSize) {
    int indexFound = binary.lastIndexOf('1', lastIndex);

    if (indexFound == -1) {
        return currentString.toString();
    }
    int padding =  maxSize - binary.length(); //Add leading "0's" to binary 

    int index = indexFound + padding;
    int charPos = indexes.get(index);

    currentString.deleteCharAt(charPos);
    process(indexFound-1, binary, currentString, indexes, maxSize);

    return currentString.toString();
}

}