在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 (kabcabcabc
?您将单个字符添加到 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中重复排列数组的主要内容,如果未能解决你的问题,请参考以下文章