【问题标题】:Algorithm to create all permutations and lengths创建所有排列和长度的算法
【发布时间】:2020-05-05 18:45:55
【问题描述】:

我希望最好在 Java 中创建一个算法。我想通过以下 char 数组并从中创建所有可能的排列和长度。

例如,循环并打印以下内容:

a
aa
aaaa
aaaaa
.... keep going ....
aaaaaaaaaaaaaaaaa ....
ab
aba
abaa .............

直到我从我的数组中找到所有可能的长度和排列。

private void method(){
    char[] data = "abcdefghiABCDEFGHI0123456789".toCharArray();
    // loop and print each time
}

我认为为此设计 10 个 for 循环会很愚蠢。我猜某种形式的递归在这里会有所帮助,但我什至无法开始。请问我能得到一些帮助吗?即使指向我开始或博客或其他东西。一直在谷歌搜索和环顾四周,存在许多排列示例,但保持固定的最大长度。似乎没有关于多重长度+排列的例子。请指教。谢谢。

【问题讨论】:

  • 我看不到您的示例输出、您的描述和示例代码如何匹配。给定给定的data 数组,如何输出aaadata 中只出现一次...
  • @MichaelKreutz 这是对密码破解的暴力破解。有现成的程序可以做到这一点,但我正在尝试创建算法的编写方式。 char 数组是我想象中的存储方式。我仍然期待以上的输出。建议存储是否应该采用不同的格式而不是这个 char 数组来实现这一点。谢谢。
  • 最长的有效字符串长度是多少? 28 岁?
  • @Eritrean 长度为 28。以单个 'a' 开头,以 9999999999999999999999999 结尾。
  • 对不起,我还没有完全明白。你试图找到的不是给定单词和该单词的子词的排列,而是替换采样,对吧?

标签: java algorithm recursion


【解决方案1】:

另一种方法是:

public class HelloWorld{
    public static String[] method(char[] arr, int length) {
      if(length == arr.length - 1) {
        String[] strArr = new String[arr.length];

        for(int i = 0; i < arr.length; i ++) {
            strArr[i] = String.valueOf(arr[i]);
        }

        return strArr;
      }


      String[] before = method(arr, length + 1);
      String[] newArr = new String[arr.length * before.length];
      for(int i = 0; i < arr.length; i ++) {
        for(int j = 0; j < before.length; j ++) {
          if(i == 0)
            System.out.println(before[j]);

          newArr[i * before.length + j] = (arr[i] + before[j]);
        }
      }

      return newArr;
    }

    public static void main(String []args){
        String[] all = method("abcde".toCharArray(), 0);

        for(int i = 0; i < all.length; i ++) {
          System.out.println(all[i]);
        }
    }
}

但是要小心,您可能会耗尽内存,否则程序将需要很长时间才能编译/运行(如果确实如此)。您正在尝试打印 3.437313508041091e+40 字符串,即 3 后跟 40 个零。

这也是 javascript 中的解决方案,因为它开始运行,但需要 4 秒才能达到 4 个字符排列,要达到 5 个字符排列,它需要大约 28 倍的时间,对于 6 个字符,它是 4 * 28 * 28等等。

const method = (arr, length) => {
  if(length === arr.length - 1)
    return arr;

  const hm = [];
  const before = method(arr, length + 1);
  for(let i = 0; i < arr.length; i ++) {
    for(let j = 0; j < before.length; j ++) {
      if(i === 0)
        console.log(before[j]);

      hm.push(arr[i] + before[j]);
    }
  }

  return hm;
};

method('abcdefghiABCDEFGHI0123456789'.split(''), 0).forEach(a => console.log(a));

【讨论】:

    【解决方案2】:
    private void method(){
        char[] data = "abcdefghiABCDEFGHI0123456789".toCharArray();
        // loop and print each time
    }
    

    根据您给定的输入,有3.43731350804×10E40 组合。 (单词的拼写结果是eighteen quadrillion fourteen trillion three hundred ninety-eight billion five hundred nine million four hundred eighty-one thousand nine hundred eighty-four。)如果我没记错的话,数学就是这样

    1  +  x  +  x^2  +  x^3  +  x^4  +  ...  +  x^n = (1 - x^n+1) / (1 - x)
    

    你的情况

    28 + 28^2 + 28^3 + .... 28^28
    

    因为你会有

    长度为 1 的字符串的 28 种组合

    长度为 2 的字符串的 28*28 组合

    长度为 3 的字符串的 28*28*28 组合

    ...

    长度为 28 的字符串的 28^28 个组合

    将它们全部打印出来需要一段时间。

    我能想到的一种方法是使用 Generex 库,这是一个用于生成与给定正则表达式匹配的字符串的 Java 库。

    Generex github。查看他们的页面了解更多信息。

    Generex maven repo。下载jar或者添加依赖。

    如果您熟悉正则表达式,那么使用generex 很简单。

    仅使用前 5 个字符的示例,将有 3905 种可能的组合

    public static void main(String[] args) {
        Generex generex = new Generex("[a-e]{1,5}");
        System.out.println(generex.getAllMatchedStrings().size());
        Iterator iterator = generex.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
    

    [a-e]{1,5} 的含义 字符 a、b、c、d、e 的任意组合,最小长度为 1,最大长度为 5

    输出

    a
    aa
    aaa
    aaaa
    aaaaa
    aaaab
    aaaac
    aaaad
    aaaae
    aaab
    aaaba
    aaabb
    aaabc
    aaabd
    aaabe
    aaac
    ....
    eeee
    eeeea
    eeeeb
    eeeec
    eeeed
    eeeee
    

    【讨论】:

      【解决方案3】:

      你可以有一个从 1 开始到 array.length 结束的 for 循环,并且在每次迭代中调用一个函数来打印该长度的所有排列。

      public void printPermutations(char[] array, int length) {
        /*
         * Create all permutations with length = length and print them
         */
      }
      
      public void method() {
        char data = "abcdefghiABCDEFGHI0123456789".toCharArray();
      
        for(int i = 1; i <= data.length; i ++) {
          printPermutations(data, i);
        }
      }
      

      【讨论】:

      • 不错的答案,但我觉得这更像是一个评论
      【解决方案4】:

      我认为以下递归可以解决您的问题:

        public static void main(String[] args) {
          final String[] data = {"a", "b", "c"};
          sampleWithReplacement(data, "", 1, 5);
        }
      
        private static void sampleWithReplacement(
            final String[] letters,
            final String prefix,
            final int currentLength,
            final int maxLength
        ) {
          if (currentLength <= maxLength) {
            for (String letter : letters) {
              final String newPrefix = prefix + letter;
              System.out.println(newPrefix);
              sampleWithReplacement(letters, newPrefix, currentLength + 1, maxLength);
            }
      
          }
        }
      

      data 指定您可能从中采样的字符。

      【讨论】:

        【解决方案5】:

        你说的是这个吗?

        public class PrintPermutations
        {
            public static String stream = "";
        
            public static void printPermutations (char[] set, int count, int length)
            {
                if (count < length)
                    for (int i = 0; i < set.length; ++i)
                    {
                        stream += set[i];
                        System.out.println (stream);
        
                        printPermutations (set, count + 1, length);
                        stream = stream.substring (0, stream.length() - 1);
                    }
            }
        
            public static void main (String[] args)
            {
                char[] set = "abcdefghiABCDEFGHI0123456789".toCharArray();
                printPermutations (set, 0, set.length);
            }
        }
        

        首先使用较小的字符串进行测试。

        【讨论】:

          【解决方案6】:

          对于长度为 28 个字符的输入字符串,此方法永远不会结束,但对于较小的输入,它将生成长度为 n 的所有排列,其中 n 是字符数。它首先打印所有长度为 1 的排列,然后打印所有长度为 2 等的排列,这与您的示例不同,但希望顺序无关紧要。

          static void permutations(char[] arr)
          {
              int[] idx = new int[arr.length];
              char[] perm = new char[arr.length];
          
              Arrays.fill(perm, arr[0]);
          
              for (int i = 1; i < arr.length; i++)
              {
                  while (true)
                  {
                      System.out.println(new String(perm, 0, i));
          
                      int k = i - 1;
                      for (; k >= 0; k--)
                      {
                          idx[k] += 1;
                          if (idx[k] < arr.length)
                          {
                              perm[k] = arr[idx[k]];
                              break;
                          }
                          idx[k] = 0;
                          perm[k] = arr[idx[k]];
                      }
                      if (k < 0)
                          break;
                  }
              }
          }
          

          测试:

          permutations("abc".toCharArray());
          

          输出:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-10-01
            • 1970-01-01
            • 1970-01-01
            • 2013-09-19
            相关资源
            最近更新 更多