在Java中重复排列数组

Posted

技术标签:

【中文标题】在Java中重复排列数组【英文标题】:Permutation of an array, with repetition, in 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!。 【参考方案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] 相同

【讨论】:

如果我正确理解问题,给出所需的排列长度

以上是关于在Java中重复排列数组的主要内容,如果未能解决你的问题,请参考以下文章

求全排列(数组有重复元素和数组无重复元素) 回溯 递归

ExpandableListView 数组列表不会按我放置的顺序排列[重复]

生成JavaScript数组的排列[重复]

按最低到最高排列数组[重复]

使用 numpy 生成数组排列的长列表(重复)

没有重复的排列算法?