【问题标题】:Permutation of an array, with repetition, in Java在Java中重复排列数组
【发布时间】:2012-10-20 21:27:33
【问题描述】:

网站上有一些类似的问题有所帮助,但我不能完全确定这个问题,所以我希望这不是重复。

这是一个家庭作业,你有一组字符 [A, B, C],并且必须使用递归来获得所有排列(重复)。我的代码是这样的:

char[] c = {'A', 'B' , 'C'};

public void printAll(char[] c, int n, int k) {
    if (k == n) {
      System.out.print(c);
      return;
    }
    else {   
      for (int j = 0; j<n; j++) {
        for (int m = 0; m<n; m++) {
           System.out.print(c[k]); 
           System.out.print(c[j]); 
           System.out.print(c[m] + "\r\n");
        }
      }
    }        
    printAll(c, n, k+1);    
}

但是,参数 n 应该定义输出的长度,所以虽然这个函数打印出长度为 3 的所有排列,但它不能执行长度为 2 的排列。我已经尝试了所有我能想到的,并仔细研究了谷歌搜索结果,我为自己无法解决看似相当简单的问题而感到恼火。

【问题讨论】:

  • 这里的“有重复”是什么意思?
  • 只是表示一个字符一旦使用,就可以再次使用。所以可能输出的数量是 3^3,而不是 3!。

标签: java arrays recursion permutation


【解决方案1】:

我使用这种带有重复排列的java实现。 A~(n,m):n = 数组长度,m = k。 m 可以大于或小于 n。

public class Permutations {


    static void permute(Object[] a, int k, PermuteCallback callback) {
        int n = a.length;

        int[] indexes = new int[k];
        int total = (int) Math.pow(n, k);

        Object[] snapshot = new Object[k];
        while (total-- > 0) {
            for (int i = 0; i < k; i++){
                snapshot[i] = a[indexes[i]];
            }
            callback.handle(snapshot);

            for (int i = 0; i < k; i++) {
                if (indexes[i] >= n - 1) {
                    indexes[i] = 0;
                } else {
                    indexes[i]++;
                    break;
                }
            }
        }
    }

    public static interface PermuteCallback{
        public void handle(Object[] snapshot);
    };

    public static void main(String[] args) {
        Object[] chars = { 'a', 'b', 'c', 'd' };
        PermuteCallback callback = new PermuteCallback() {

            @Override
            public void handle(Object[] snapshot) {
                for(int i = 0; i < snapshot.length; i ++){
                    System.out.print(snapshot[i]);
                }
                System.out.println();
            }
        };
        permute(chars, 8, callback);
    }

}

示例输出是

aaaaaaaa
baaaaaaa
caaaaaaa
daaaaaaa
abaaaaaa
bbaaaaaa
...
bcdddddd
ccdddddd
dcdddddd
addddddd
bddddddd
cddddddd
dddddddd

【讨论】:

    【解决方案2】:

    这里是用重复生成给定字符串的排列的 c# 版本:

    (基本思想是-长度为'n'且重复次数为n^n的字符串的排列数)。

    string[] GetPermutationsWithRepetition(string s)
            {
                s.ThrowIfNullOrWhiteSpace("s");
                List<string> permutations = new List<string>();
                this.GetPermutationsWithRepetitionRecursive(s, "",
                    permutations);
                return permutations.ToArray();
            }
            void GetPermutationsWithRepetitionRecursive(string s, string permutation, List<string> permutations)
            {
                if(permutation.Length == s.Length)
                {
                    permutations.Add(permutation);
                    return;
                }
                for(int i =0;i<s.Length;i++)
                {
                    this.GetPermutationsWithRepetitionRecursive(s, permutation + s[i], permutations);
                }
            }
    

    下面是对应的单元测试:

    [TestMethod]
            public void PermutationsWithRepetitionTests()
            {
                string s = "";
                int[] output = { 1, 4, 27, 256, 3125 };
                for(int i = 1; i<=5;i++)
                {
                    s += i;
                    var p = this.GetPermutationsWithRepetition(s);
                    Assert.AreEqual(output[i - 1], p.Length);
                }
            }
    

    【讨论】:

      【解决方案3】:

      如果我理解正确,您会得到一组字符 c 和所需的长度 n

      从技术上讲,没有重复排列这样的事情。我假设您想要所有长度为 n 的字符串以及来自 c 的字母。

      你可以这样做:

      to generate all strings of length N with letters from C
       -generate all strings of length N with letters from C
           that start with the empty string.
      
      to generate all strings of length N with letters from C
         that start with a string S
       -if the length of S is N
        -print S
       -else for each c in C
        -generate all strings of length N with letters from C that start with S+c
      

      在代码中:

      printAll(char[] c, int n, String start){
        if(start.length >= n){
          System.out.println(start)
        }else{
          for(char x in c){ // not a valid syntax in Java
            printAll(c, n, start+x);
          }
        }
      }
      

      【讨论】:

      • 先生,您不只是一个绅士和一个学者。你是一个王子,一个绅士,一个学者。网上的其他一些人提出了类似的建议,除了使用数组而不是字符串。但是,您的解释要清楚得多。
      • 作为参考,如果有人感兴趣,这里是最终函数,其中 n 参数控制打印的每一行的长度: public void printAll3(char[] c, int n, int k, 字符串 s) { if (s.length() >=n) {System.out.print(s + "\r\n"); return;} else if (k
      • @JanDvorak 我知道这是旧的,但我有一个类似的问题我试图解决,我修改了它并且它完全有效。但是我不明白你的最终调用 printAll(c,n ,start+x) 有效。我把它打印出来,在最初的几个电话(a、aa、aaa、aab、aac、ab、aba)中开始是这样的。我真的不明白为什么它最终不是(abc,abcabc,abcabcabc)。我希望你能解释一下。我一直在尝试跟踪它,并且我知道每次 print all 在循环内调用自己时,它都会多次调用自己。无论如何,如果可以的话,我想要更多的解释。
      • @MichelleJS 为什么会是abcabcabc?您将单个字符添加到 start,然后回溯并在同一位置添加不同的字符。在第一次调用(start == "")中:start.length == 0,所以它转到else 分支。 C 的第一个字符是a,所以在第一次迭代中x == 'a'"" + 'a' == "a",所以第一个递归调用是printAll("abc", 3, "a")。如果您在循环内执行printAll(c, n, start+c),您描述的行为将会发生 - 在这种情况下,x 最终将未被使用。
      • 非常感谢。我把它全部画在一张纸上以便理解。我现在必须不重复地做另一件事。我不知道如何修改这段代码来做到这一点,但这是一个很好的开始。
      【解决方案4】:

      我刚刚有了一个想法。如果您添加一个隐藏字符(H 表示隐藏)[A, B, C, H],然后执行它的所有固定长度排列(您说您知道该怎么做)。然后,当您阅读它时,您会停在隐藏的字符处,例如[B,A,H,C] 将变为 (B,A)。

      嗯,缺点是您必须跟踪您创建的那些,尽管 [B,H,A,C] 与 [B,H,C,A] 相同

      【讨论】:

      • 如果我正确理解问题,给出所需的排列长度
      猜你喜欢
      • 2019-08-11
      • 2015-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多