【问题标题】:java - Transposition Cipher Enumerationjava - 转置密码枚举
【发布时间】:2017-12-14 17:12:22
【问题描述】:

注意:我之前删除了这篇文章,因为我发现了以下post,但我不知道如何将其应用于我的问题。

我正在研究转置密码解码器。我已经解决了静态列的问题(1,2,3,4 按顺序排列),但我不确定如何创建每个可能的长度排列的数组(作为参数给出),我理解最简单的方法是某种递归方法,但是在尝试此方法时,我一直在努力中迷失方向。 (一整天都在写代码,很累)

示例数组将包含:

1,2,3,4,5,6
2,1,3,4,5,6
2,3,1,4,5,6
...

【问题讨论】:

    标签: java encryption cryptography


    【解决方案1】:

    困惑了一阵子,尝试了一些不同的东西,我的一个朋友(这里不是用户)给了我以下java解决方案:

    public static void main(String[] args) {
            Nibba nib = new Nibba();
            List<Character> characterSet = new ArrayList<>();
            characterSet.add('1');
            characterSet.add('2');
            characterSet.add('3');
            characterSet.add('4');
            characterSet.add('5');
            characterSet.add('6');
    
            List<String> perms = nib.generatePermutations(characterSet);
            // filter only the permutations of length 6
            perms = perms.stream().filter(p -> p.length() == characterSet
                    .size()).collect(Collectors.toList());
            for (String s : perms) {
                System.out.println(s);
            }
            System.out.println("Total permutations = " + perms.size());
        }
    
        private List<String> generatePermutations(List<Character> characterSet) {
            List<String> permutations = new ArrayList<>();
    
            for (int idx = 0; idx < characterSet.size(); idx++) {
                char character = characterSet.get(idx);
    
                // Initialise first "permutation"
                if (idx == 0) {
                    permutations.add(String.valueOf(character));
                    continue;
                }
    
                ArrayList<String> oldPerms = new ArrayList<>(permutations);
                for (String subPermutation : oldPerms) {
                    insertPermutations(permutations, subPermutation, character);
                }
            }
    
            return permutations;
        }
    
        /**
         * Insert permutations into the given list
         *
         * @param list the list
         * @param str  the string
         * @param c    the character to insert at each point in the string
         */
        private void insertPermutations(List<String> list, String str, char c) {
            for (int i = 0; i <= str.length(); i++) {
                String newStr = str.substring(0, i) + c + str.substring(i);
                list.add(newStr);
            }
        }
    

    【讨论】:

      【解决方案2】:

      回想一下,n 项有 n! 排列。 n!可以这样理解:

      1.   There are `n` options for choosing the first item.
      2.   There are `n-1` items remaining from which to choose the second item
      ...
      n-1. There are `2` options left for the `n-1`-th item.
      n.   There is only 1 item left for the `n`-th position.
      

      因此,对于如何订购商品,共有(n) * (n-1) * (n-2) * ... (2) * (1) = n! 种选择。

      这直接揭示了一种使用混合基数编号方案枚举排列的方法。在这个方案中,最重要的数字将是基数n,下一个最重要的数字将是基数n-1..等。

      您可以使用这样的混合基数以下列方式选择排列:

      1. 使用最高有效位从数组中选择一个元素(注意第一个数字范围从[0, n-1],并且有n元素可供选择,因此您可以将其用作项的索引来选择。)
      2. 从数组中删除选定的元素,记录它是置换数组的第一个元素,并将其余元素压缩到数组的前面。
      3. 使用倒数第二位从剩余的项目中选择一个元素(注意这个数字的取值范围是[0, n-2],还有n-1位剩余)
      4. 删除选定元素,将其记录为置换数组中的第二个元素
      5. 重复直到所有项目都被选中。

      如果我们使用数组来表示小端数字顺序的混合基数,那么我们将有以下内容:

      int mixed_radix[n] = {0};
      

      您可以通过以下方式增加这个混合基数:

      //Increment the least-significant digit
      mixed_radix[0]++;
      
      //Ripple overflow toward the most-significant digit
      for(i=0; i<n; i++) {
        if(mixed_radix[i] > i) {
          mixed_radix[i] = 0;
          if(i < n-1)mixed_radix[i+1]++;
        }
        else {
          break;
        }
      }
      

      所以我们有一种方法可以将混合基数初始化为零,然后将它递增到每个可能的值,一旦它回绕到零就停止。 (或在n!-1 递增之后...)

      总而言之,有一个可爱的数字技巧可以让这变得更简单:您可以通过以下方式从整数中解压缩那个丑陋的混合基数:

      我们知道有n 项的n! 排列;对于[0, n!-1] 范围内的任何整数val,以下提供了整数值和混合基数之间的双射映射:

      int working = val;  //val in the range [0, n!-1]
      for(j=0 j<n; j++) {
        mixed_radix[j] = working % (j+1);
        working /= (j+1);
      }
      

      因此,将这个“解包”循环嵌入到在0 到n!-1 范围内运行val 的外循环中是一种更密集的枚举混合基数(枚举可能的排列)的方法。它还为每个排列分配一个整数,有效地命名它们。 :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多