简体   繁体   English

智能方式生成排列和String的组合

[英]Smart way to generate permutation and combination of String

String database[] = {'a', 'b', 'c'};

I would like to generate the following strings sequence, based on given database . 我想基于给定的database生成以下字符串序列。

a
b
c
aa
ab
ac
ba
bb
bc
ca
cb
cc
aaa
...

I can only think of a pretty "dummy" solution. 我只能想到一个非常“虚拟”的解决方案。

public class JavaApplication21 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        char[] database = {'a', 'b', 'c'};

        String query = "a";
        StringBuilder query_sb = new StringBuilder(query);
        for (int a = 0; a < database.length; a++) {
            query_sb.setCharAt(0, database[a]);
            query = query_sb.toString();                    
            System.out.println(query);            
        }

        query = "aa";
        query_sb = new StringBuilder(query);
        for (int a = 0; a < database.length; a++) {
            query_sb.setCharAt(0, database[a]);    
            for (int b = 0; b < database.length; b++) {    
                query_sb.setCharAt(1, database[b]);    
                query = query_sb.toString();                    
                System.out.println(query);
            }
        }

        query = "aaa";
        query_sb = new StringBuilder(query);
        for (int a = 0; a < database.length; a++) {
            query_sb.setCharAt(0, database[a]);    
            for (int b = 0; b < database.length; b++) {    
                query_sb.setCharAt(1, database[b]);    
                for (int c = 0; c < database.length; c++) {                    
                    query_sb.setCharAt(2, database[c]);                        
                    query = query_sb.toString();                    
                    System.out.println(query);
                }
            }
        }
    }
}

The solution is pretty dumb. 解决方案非常愚蠢。 It is not scale-able in the sense that 从某种意义上讲,它不具有可扩展性

  1. What if I increase the size of database ? 如果我增加database的大小怎么办?
  2. What if my final targeted print String length need to be N? 如果我的最终目标打印字符串长度需要为N,该怎么办?

Is there any smart code, which can generate scale-able permutation and combination string in a really smart way? 是否有任何智能代码,可以以非常智能的方式生成可扩展的排列和组合字符串?

You should check this answer: Getting every possible permutation of a string or combination including repeated characters in Java 您应该检查以下答案: 获取字符串或组合的所有可能的排列,包括Java中的重复字符

To get this code: 要获得此代码:

public static String[] getAllLists(String[] elements, int lengthOfList)
{

    //lists of length 1 are just the original elements
    if(lengthOfList == 1) return elements; 
    else {
        //initialize our returned list with the number of elements calculated above
        String[] allLists = new String[(int)Math.pow(elements.length, lengthOfList)];

        //the recursion--get all lists of length 3, length 2, all the way up to 1
        String[] allSublists = getAllLists(elements, lengthOfList - 1);

        //append the sublists to each element
        int arrayIndex = 0;

        for(int i = 0; i < elements.length; i++){
            for(int j = 0; j < allSublists.length; j++){
                //add the newly appended combination to the list
                allLists[arrayIndex] = elements[i] + allSublists[j];
                arrayIndex++;
            }
        }
        return allLists;
    }
}

public static void main(String[] args){
    String[] database = {"a","b","c"};
    for(int i=1; i<=database.length; i++){
        String[] result = getAllLists(database, i);
        for(int j=0; j<result.length; j++){
            System.out.println(result[j]);
        }
    }
}

Although further improvement in memory could be made, since this solution generates all solution to memory first (the array), before we can print it. 虽然可以进一步改进内存,但是由于此解决方案首先生成所有内存解决方案(数组),然后才能打印它。 But the idea is the same, which is to use recursive algorithm. 但是这个想法是一样的,即使用递归算法。

This smells like counting in binary: 这有点像二进制计数:

  • 001 001
  • 010 010
  • 011 011
  • 100 100
  • 101 101
  • ... ...

My first instinct would be to use a binary counter as a "bitmap" of characters to generate those the possible values. 我的第一直觉是使用二进制计数器作为字符的“位图”来生成可能的值。 However, there are several wonderful answer to related questions here that suggest using recursion. 但是,这里有相关问题的几个很好的答案建议使用递归。 See 看到

Java implementation of your permutation generator:- 你的置换生成器的Java实现: -

public class Permutations {


    public static void permGen(char[] s,int i,int k,char[] buff) {
        if(i<k) {
            for(int j=0;j<s.length;j++) {

                buff[i] = s[j];
                permGen(s,i+1,k,buff);
            }
        }       
        else {

         System.out.println(String.valueOf(buff)); 

        }

    }

    public static void main(String[] args) {
        char[] database = {'a', 'b', 'c'};
        char[] buff = new char[database.length];
        int k = database.length;
        for(int i=1;i<=k;i++) {
            permGen(database,0,i,buff);
        }

}

}

Ok, so the best solution to permutations is recursion. 好的,所以排列的最佳解决方案是递归。 Say you had n different letters in the string. 假设你在字符串中有n个不同的字母。 That would produce n sub problems, one for each set of permutations starting with each unique letter. 这将产生n个子问题,每个问题以每个唯一字母开头的一组排列。 Create a method permutationsWithPrefix(String thePrefix, String theString) which will solve these individual problems. 创建一个方法permutationsWithPrefix(String thePrefix, String theString) ,它将解决这些个别问题。 Create another method listPermutations(String theString) a implementation would be something like 创建另一个方法listPermutations(String theString)实现就像

void permutationsWithPrefix(String thePrefix, String theString) {
   if ( !theString.length ) println(thePrefix + theString);
   for(int i = 0; i < theString.length; i ++ ) {
      char c = theString.charAt(i);
      String workingOn = theString.subString(0, i) + theString.subString(i+1);   
      permutationsWithPrefix(prefix + c, workingOn);
   }
} 

void listPermutations(String theString) {
   permutationsWithPrefix("", theString);
}

i came across this question as one of the interview question. 我把这个问题作为面试问题之一。 Following is the solution that i have implemented for this problem using recursion. 以下是我使用递归实现此问题的解决方案。

public class PasswordCracker {

private List<String> doComputations(String inputString) {

    List<String> totalList =  new ArrayList<String>();
    for (int i = 1; i <= inputString.length(); i++) {

        totalList.addAll(getCombinationsPerLength(inputString, i));
    }
    return totalList;

}

private ArrayList<String> getCombinationsPerLength(
        String inputString, int i) {

    ArrayList<String> combinations = new ArrayList<String>();

    if (i == 1) {

        char [] charArray = inputString.toCharArray();
        for (int j = 0; j < charArray.length; j++) {
            combinations.add(((Character)charArray[j]).toString());
        }
        return combinations;
    }
    for (int j = 0; j < inputString.length(); j++) {

        ArrayList<String> combs = getCombinationsPerLength(inputString, i-1);
        for (String string : combs) {
            combinations.add(inputString.charAt(j) + string);
        }
    }

    return combinations;
}
public static void main(String args[]) {

    String testString = "abc";
    PasswordCracker crackerTest = new PasswordCracker();
    System.out.println(crackerTest.doComputations(testString));

}
}

For anyone looking for non-recursive options, here is a sample for numeric permutations (can easily be adapted to char . numberOfAgents is the number of columns and the set of numbers is 0 to numberOfActions : 为寻找非递归的选项,这里是数字排列的样本(可以很容易地适应charnumberOfAgents是列数和组数字是0numberOfActions

    int numberOfAgents=5;
    int numberOfActions = 8;
    byte[][]combinations = new byte[(int)Math.pow(numberOfActions,numberOfAgents)][numberOfAgents];

    // do each column separately
    for (byte j = 0; j < numberOfAgents; j++) {
        // for this column, repeat each option in the set 'reps' times
        int reps = (int) Math.pow(numberOfActions, j);

        // for each column, repeat the whole set of options until we reach the end
        int counter=0;
        while(counter<combinations.length) {
            // for each option
            for (byte i = 0; i < numberOfActions; i++) {
                // save each option 'reps' times
                for (int k = 0; k < reps; k++)
                    combinations[counter + i * reps + k][j] = i;
            }
            // increase counter by 'reps' times amount of actions
            counter+=reps*numberOfActions;
        }
    }

    // print
    for(byte[] setOfActions : combinations) {
        for (byte b : setOfActions)
            System.out.print(b);
        System.out.println();
    }
// IF YOU NEED REPEATITION USE ARRAYLIST INSTEAD OF SET!!

import java.util.*;
public class Permutation {

    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        System.out.println("ENTER A STRING");
        Set<String> se=find(in.nextLine());
        System.out.println((se));
    }
    public static Set<String> find(String s)
    {
        Set<String> ss=new HashSet<String>();
        if(s==null)
        {
            return null;
        }
        if(s.length()==0)
        {
            ss.add("");
        }
        else
        {
            char c=s.charAt(0);
            String st=s.substring(1);
            Set<String> qq=find(st);
            for(String str:qq)
            {
                for(int i=0;i<=str.length();i++)
                {
                    ss.add(comb(str,c,i));
                }
            }
        }
        return ss;

    }
    public static String comb(String s,char c,int i)
    {
        String start=s.substring(0,i);
        String end=s.substring(i);
        return start+c+end;
    }

}


// IF YOU NEED REPEATITION USE ARRAYLIST INSTEAD OF SET!!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM