如果ABC通过,则返回[A,AB,BC,ABC,AC,B,C] 如果ABCD通过则返回[A,AB,BC,CD,ABC,AC,ACD,B,BCD,BD,ABD,AD,C,D,ABCD]
表示AB和BA始终相同,ABC,BAC和ACB也相同。
我最后写下了代码,但似乎工作(不确定)。
public static Set<String> getAnyPermutations(String s,String strInput) {
Set<String> resultSet = new HashSet<>();
char[] inp = strInput.toCharArray();
for(int i=0; i<inp.length; i++) {
String temp =s+String.valueOf(inp[i]);
resultSet.add(temp);
if(i+1<=inp.length)
resultSet.addAll(getAnyPermutations(temp, String.valueOf(Arrays.copyOfRange(inp, i+1, inp.length))));
}
return resultSet;
}
我的问题是,我想从方法中删除第一个参数(String s),因为它只用于内部计算,或者如果不可能,那么确保用户总是传递“”值或者我可以重置对于此方法的第一次(非递归)调用,它为“”。我很困惑如何在递归函数中做到这一点。 如果您怀疑除了这种情况可能会失败,请添加评论。
条件,所有必须仅在此函数内完成,不能创建其他方法。
答案 0 :(得分:4)
只需在此功能内完成,不能创建其他功能。
然后你无法做到。该函数没有(合理) *知道它是自己调用还是被另一个函数调用的方式。
有许多涉及创建另一个功能的解决方案。一个可能符合你的要求,取决于他们实际表达的方式,就是让函数定义一个lambda来完成工作,并让lambda调用自己。例如,getAnyPermutations
实际上不是递归的,它将包含递归函数。
但是这可能超出了界限,这取决于上面引用的确切含义,因为lambda是另一个函数,而不是可以从外部访问的函数。
* un 合理的方法是检查堆栈跟踪,您可以从Thread.currentThread().getStackTrace
获取。
答案 1 :(得分:2)
您可以将当前方法更改为私有方法,并使用带有一个参数的公共方法将其连接,例如:
private static Set<String> getAnyPermutations(String s,String strInput) {
Set<String> resultSet = new HashSet<>();
char[] inp = strInput.toCharArray();
for(int i=0; i<inp.length; i++){
String temp =s+String.valueOf(inp[i]);
resultSet.add(temp);
if(i+1<=inp.length)
resultSet.addAll(getAnyPermutations(temp, String.valueOf(Arrays.copyOfRange(inp, i+1, inp.length))));
}
return resultSet;
}
现在,您可以向用户公开一个参数方法,然后用户将调用上述方法,例如:
public static Set<String> getAnyPermutations(String strInput) {
return getAnyPermutations("", strInput);
}
<强>更新强>
如果您根本无法创建任何其他方法,那么唯一的选择就是使用var-args
。但是,这需要更改实现,并且实际上并不限制用户传递多个值。
答案 2 :(得分:2)
您可以重写此特定算法,以便它不需要将状态传递到递归调用的调用。
(以Java为中心的伪代码):
Set<String> getAnyPermutations(String str) {
if(str.length() == 0) {
return Collections.emptySet();
}
String head = str.substring(0,1);
String tail = str.substring(1);
Set<String> permutationsOfTail = getAnyPermutations(tail);
Set<String> result = new HashSet();
// Head on its own
// For input 'ABC', adds 'A'
result.add(head);
// All permutations that do not contain head
// For input 'ABC', adds 'B', 'C', 'BC'
result.addAll(permutationsOfTail);
// All permutations that contain head along with some other elements
// For input 'ABC', adds 'AB, 'AC', 'ABC'
for(String tailPerm : permutationsOfTail) {
result.add(head + tailPerm);
}
return result;
}
这符合您不创建任何额外方法的目的 - 但请注意,如果将for
循环提取到允许Set<String> prefixEachMember(String prefix, Set<String> strings)
的新方法result.addAll(prefixEachMember(head,permutationsOfTail))
中,则代码会更干净。< / p>
然而并非总能做到这一点,有时你做想要携带状态。一种方式是你要求避免的方式,但我会将其包括在我的答案中,因为它是实现目标的一种清晰而通用的方式。
public Foo myMethod(Bar input) {
return myMethod(new HashSet<Baz>(), input);
}
private Foo myMethod(Set<Baz> state, Bar input) {
if(...) {
return ...;
} else {
...
return myMethod(..., ...);
}
}
这里,第一种方法是您的公共API,其中不需要collector / state参数。第二种方法是私有worker方法,最初使用空状态对象调用它。
另一个选择是引用一个对象字段。但是,我建议不要这样做,因为当递归代码引用全局对象时,它会变得混乱。
答案 3 :(得分:2)
您始终可以将递归方法转换为其迭代等效方法 - 例如 Way to go from recursion to iteration
在迭代版本中,很容易不公开状态参数(现在只需要在迭代方法的开头初始化它)。
这一般来说不太实用(但我相信这个问题的目的更具理论性,否则它只是暴露另一种方法的好方法)。
此外,在这种特殊情况下,您可能会考虑这种简单的迭代方法(虽然它不是通过直接翻译给定代码获得的):
public static Set<String> getAnyPermutations(String strInput) {
Set<String> resultSet = new HashSet<>();
char[] inp = strInput.toCharArray();
for (int bitMask = 0; bitMask < (1 << inp.length); bitMask++) {
StringBuilder str = new StringBuilder();
for (int i = 0; i < inp.length; i++) {
if ((bitMask & (1 << i)) != 0) {
str.append(inp[i]);
}
}
if (str.length() > 0) {
resultSet.add(str.toString());
}
}
return resultSet;
}