4

需要帮助解决这个让我烦恼的简单事情。我见过许多类似的算法,但我想以完全规定的方式做到这一点,以达到给定字符集数组中所有可能的组合/排列。

让我们举一个密码破解暴力破解的例子

例如 char[] charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();

陈述方式:

就像这样。对于当前示例。

a,b,c,d......z     then at last index "z".  

it goes like      

aa,ab,ac....az.        then      

ba,bb,bc,bd........bz          then

same for ca, cb, and so on.

aaaa,aaab,aaac......aaaz   then

baaa,baab,baac.......baaz   to      zzzzzzzzzzzzzzzzzzzzzzzzzz

到目前为止我达到的代码:

(虽然不是一个解决方案)是具有与字符集数组长度一样多的 for 循环。那太疯狂了。这工作正常。但我需要聪明的。

public class Bruteforcer {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
          char[] charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();


         int currentIndex = 0;
         String currentString = "";

         for (int i = 0; i < charset.length; i++) {
            char currentChar = charset[i];

             for (int j = 0; j < charset.length; j++) {

                 char c = charset[j];
                 currentString =  "" +currentChar + c;
                 System.out.println(currentString);

             }


         }


    }
}
4

7 回答 7

8

要在不递归的情况下解决此问题,保留当前结果的索引数组会有所帮助。这是一个模板类,它将产生您正在寻找的结果:

public abstract class Bruteforce
{
  public void generate( char[] input ) {
    char[] result = new char[input.length];
    int[] index = new int[input.length];

    // initialize the arrays.
    Arrays.fill(result, 0, result.length, input[0]);
    Arrays.fill(index,  0, index.length, 0);

    // loop over the output lengths.
    for( int length = 1; length <= input.length; length++ ) {
      int updateIndex = 0;
      do {
        element(result, 0, length);

        // update values that need to reset.
        for(updateIndex = length-1;
            updateIndex != -1 && ++index[updateIndex] == input.length;
            result[updateIndex] = input[0], index[updateIndex] = 0, updateIndex--);

        // update the character that is not resetting, if valid
        if( updateIndex != -1 ) result[updateIndex] = input[index[updateIndex]];
      }
      while(updateIndex != -1);
    }
  }
  public void generate( String input ) {
    generate(input.toCharArray());
  }
  public abstract void element(char[] result, int offset, int length);
}

然后,您可以扩展模板以将每个元素打印到 STDOUT:

new Bruteforce() {
  public void element(char[] result, int offset, int length) {
    System.out.println(new String(result, offset, length));
  }
}.generate("ABCDEFGHIJKLMNOPQRSTUVWXYZ");

注意:此代码假定输入字符串不包含任何重复字符。

于 2013-09-08T20:27:40.337 回答
4

您需要使用递归。算法的复杂度是指数级的。我希望我理解这个问题。

public class Generator {
    private char[] charset;

    public Generator()
    {
        charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
    }


    public void generate(String str, int pos, int length)
    {
        if (length == 0) {
            System.out.println(str);
        } else {
            for (int i = pos; i < charset.length; i++) {
                generate(str + charset[i], i, length - 1);
            }
        }
    }

    public static void main(String[] args)
    {
        Generator test = new Generator();
        //test.generate("", 1);
        for (int length = 1;  length < 5; length++) // Change 5 with the length of charset
            test.generate("", 0, length);
    }

}
于 2013-09-08T16:02:24.323 回答
4
public class Generator {

    private char[] charset;

    private int min; //var added for min char length
    private int max; //var added for max char length

    public Generator() {
        charset = "abcdefghijklmnopqrstuvwxyzAEIOU0123456789!@#$%^&*()-_+=~`[]{}|:;<>,.?/BCDFGHJKLMNPQRSTVWXYZ".toCharArray();
        min = 2; //char min start
        max = 5; //char max end 
    }

    public void generate(String str, int pos, int length) {
        if (length == 0) {
            System.out.println(str);
        } else {

            //This if statement resets the char position back to the very first character in the character set ('a'), which makes this a complete solution to an all combinations bruteforce! 
            if (pos != 0) {
                pos = 0;
            }

            for (int i = pos; i < charset.length; i++) {
                generate(str + charset[i], i, length - 1);
            }
        }
    }

    public static void main(String[] args) {
        Generator bruteforce = new Generator();

        for (int length = bruteforce.min; length < bruteforce.max; length++) // Change bruteforce.min and bruteforce.max for number of characters to bruteforce. 
            bruteforce.generate("", 0, length); //prepend_string, pos, length 
    }
}

我已经修改了上面rendon的示例- https://stackoverflow.com/revisions/18685721/1 注意:它允许所有组合,并添加了最小和最大变量

于 2015-07-12T22:56:16.810 回答
3

您可以使用 recursion 和几个循环。

public static void printCombinations(int length) {
    printCombinations(new char[length], 0, 0);
}

private static void printCombinations(char[] chars, int idx, int mask) {
    if (idx == chars.length) {
        System.out.println(chars);
        return;
    }
    for (int i = 0; i < 26; i++) {
        int mask2 = 1 << i;
        if ((mask2 & mask) == 0) {
            chars[idx] = (char) ('A' + i);
            printCombinations(chars, idx + 1, mask | mask2);
        }
    }
}

public static void main(String[] args) throws Exception {
    for (int i = 1; i <= 3; i++)
        printCombinations(i);
}

印刷

A
B
...
ZYWX ... DCBA

一个组合没有重复的字符,所以它不会是 ZZZZZ ......

于 2013-09-08T15:55:35.703 回答
1

更面向对象的解决方案

使用已知长度

final String target = "ABC";
final char[] charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
BruteForce.bruteForce(charset, 5, string -> {
    System.out.println(string);
    return string.equals(target);
});

使用未知长度

final String target = "ABC";
final char[] charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();

// Use your looping method of choice
boolean found = false;
int length = 1;
while (!found) {
    found = BruteForce.bruteForce(charset, length, string -> {
        System.out.println(string);
        return string.equals(target);
    });
    length++;
}

执行

public class BruteForce {

    public static boolean bruteForce(@NonNull final char[] input, final int length, @NonNull final Closure closure) {
        final char[] chars = new char[length];
        final IncrementalCharSequence incrementalCharSequence = new IncrementalCharSequence(input, chars);

        // Use your looping method of choice
        do {
            if (closure.compare(new String(chars))) {
                return true;
            }
        } while (incrementalCharSequence.increment());
        return false;
    }
}
public interface Closure {

    boolean compare(@NonNull final String string);
}
public class IncrementalCharSequence {

    @NonNull
    private final char[] input;

    @Nullable
    private final IncrementalCharSequence subIncrementalCharSequence;

    @NonNull
    private final char[] chars;

    private final int index;

    private int currentIndex;

    public IncrementalCharSequence(@NonNull final char[] input, @NonNull final char[] chars) {
        this(input, chars, 0);
    }

    private IncrementalCharSequence(@NonNull final char[] input, @NonNull final char[] chars, final int index) {
        this.input = input;
        this.chars = chars;
        this.index = index;
        if (index + 1 < chars.length) {
            this.subIncrementalCharSequence = new IncrementalCharSequence(input, chars, index + 1);
        } else {
            this.subIncrementalCharSequence = null;
        }
        currentIndex = 0;
        chars[index] = input[currentIndex];
    }

    /**
     * Increment the char sequence
     *
     * @return {@code true} if incremented, {@code false} if rolled over to zero index
     */
    public boolean increment() {
        if (subIncrementalCharSequence != null && subIncrementalCharSequence.increment()) {
            return true;
        } else if (currentIndex < input.length) {
            chars[index] = input[currentIndex];
            currentIndex++;
            return true;
        } else {
            currentIndex = 0;
            chars[index] = input[currentIndex];
            return false;
        }
    }
}
于 2020-03-08T18:59:35.573 回答
0

一个伪代码

initialize globalComb, an empty array of strings (to keep all combination)
initialize prevComb, an array of strings with an empty string (the previous set of combination)
while(the length of first string in prevComb is not of desired length)
    initialize temp,  an empty array of strings (a temporary one)
    for(each string s in prevComb)
        for(each char c in the alphabet)
            insert s + c in temp
            insert s + c in globalComb
        end for
    end for
    lastComb = temp
return globalComb

的大小globalComb必须是 sum(k=1, k=desired length)26^k。如果所需的长度是 26,我怀疑普通笔记本电脑是否可以容纳这样的字符串数组。您可以将字符串打印出来,而不是存储在全局数组中。

于 2013-09-08T16:00:24.897 回答
-2

我想出了这段代码,它将运行到 8 个小写/字母,
例如。如果您只使用大写字母 A 到 Z:
A
B
...
...
ZZZZZZZY
ZZZZZZZZ

char[] ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
for (int i = 0; i < ch.length; i++) {
    char c1 = ch[i];
    for (int j = 0; j < ch.length; j++) {
        char c2 = ch[j];
        for (int k = 0; k < ch.length; k++) {
            char c3 = ch[k];
            for (int l = 0; l < 10; l++) {
                char c4 = ch[l];
                for (int m = 0; m < 10; m++) {
                    char c5 = ch[m];
                    for (int n = 0; n < 10; n++) {
                        char c6 = ch[n];
                        for (int o = 0; o < 10; o++) {
                            char c7 = ch[o];
                            for (int p = 0; p < 10; p++) {
                                char c8 = ch[p];
                                currentString = "" + c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8;
                                System.out.println(currentString);

                            }
                        }
                    }
                }
            }
        }
    }
}
于 2018-09-12T20:57:25.177 回答