我在java中做了一个单词unscrambler。现在我有一个程序,可以打印从3个或更多字母(没有重复)的单词中选择的3个字母的所有重新排列。例如,如果参数是 abcd ,它将打印出:
[[abc,abd,acb,acd,adb,adc,bac,bad,bca,bcd,bda,bdc,cab,cad,cba,cbd,cda,cdb,dab,dac,dba,dbc,dca ,dcb]]
我正在使用排列填充2D数组列表。现在,2D数组中只有一个数组,其中包含3个字母的排列。我希望2D数组具有1个字母,2个字母,3个字母等的permations数组,停止在单词的长度。问题是我需要一个可变数量的嵌套for循环来完成这个。对于3个字母的排列,我有3个嵌套for循环。每个循环遍历参数中的字母。
public static void printAllPermuations(String word)
{
int len = word.length();
ArrayList<String> lets = new ArrayList<String>();
//this array of letters allows for easier access
//so I don't have to keep substringing
for (int i = 0; i < len; i++)
{
lets.add(word.substring(i, i + 1));
}
ArrayList<ArrayList<String>> newWords = new ArrayList<ArrayList<String>>();
newWords.add(new ArrayList<String>());
for (int i = 0; i < len; i++)
{
for (int j = 0; j < len; j++)
{
for (int k = 0; k < len; k++)
{
if (i != j && i != k && j != k)
//prevents repeats by making sure all indices are different
{
newWords.get(0).add(lets.get(i) + lets.get(j) + lets.get(k));
}
}
}
}
System.out.println(newWords);
}
我看过其他帖子,我听说递归可以解决这个问题。不过,我不知道如何实现这一点。而且我也看到了一些我不理解的复杂解决方案。无论是否涉及递归,我都要求最简单的解决方案。
答案 0 :(得分:3)
使用递归方法,您可以将一个循环放在函数中,将循环参数传递给该函数。然后在函数循环中,它调用它来嵌套另一个循环。
void loopFunction(ArrayList<ArrayList<String>> newWords, int level) {
if (level == 0) { // terminating condition
if (/* compare the indices by for example passing down a list with them in */)
{
newWords.get(...).add(...);
}
} else {// inductive condition
for (int i = 0; i < len; i++) {
loopFunction(newWords, level-1);
}
}
}
因此,对于您的示例,您需要3级递归,因此您可以使用以下命令开始递归:
loopFunction(newWords, 3);
修改强>
由于你遇到麻烦,这是一个有效的版本。它保留了要比较的索引列表,并随着它的建立而构建字符串。重新排列的单词被添加到每个级别的2D阵列以获得所有长度的单词。使用递归最简单的方法是在功能上思考而不是更改并保持变量不可变(不可更改)。虽然我更新indices
而不是为了方便而创建新副本,但此代码主要是这样做的。
void loopFunction(ArrayList<String> lets, ArrayList<ArrayList<String>> newWords, int level, ArrayList<Integer> indices, String word) {
if (level == 0) { // terminating condition
return;
} else { // inductive condition
for (int i = 0; i < lets.size(); i++) {
if (!indices.contains(i)) { // Make sure no index is equal
int nextLevel = level-1;
String nextWord = word+lets.get(i);
newWords.get(level-1).add(nextWord);
indices.add(i);
loopFunction(lets, newWords, nextLevel, indices, nextWord);
indices.remove((Integer) i);
}
}
}
}
答案 1 :(得分:0)
我不会给你实际的代码,但是这应该让你知道递归的样子(我相信还有其他的递归方法:P)
void findAllCombination(String tmpResult,
String rawString,
int noOfChar,
List<String> allCombinations) {
if (tmpResult.size() == noOfChar) {
allCombinations.add(tmpResult );
} else {
for (i in 0 to rawString.size()) {
findAllCombination(tmpResult + rawString[i],
rawString.removeCharAt(i),
noOfChar,
allCombinations);
}
}
}
List<String> foo(String input, int level) {
List<String> allResults = ...;
findAllCombination("", input, level, allResults);
return allResults;
}
主递归部分是findAllCombination
。这个想法是严格的前进。对于找到所有排列的方法是,对于我们拥有的rawString输入,我们逐个取出字符,并追加到先前找到的tmpResult,并使用该tmpResult进行进一步处理。一旦我们达到了tmpResult足够长的时间点,那么我们将tmpResult放到结果allCombinations
列表中。
(foo()方法只是为了让您的调用更容易:实际完成工作的P代码只有6行,不包括只有括号的行而忽略了为了更好的可读性而故意破坏的行)
答案 2 :(得分:0)
基于@DrYap所说的,我写了这个(它与他有点不同):
以下是启动它的代码:
for(int i = 1; i <= len; i++)
{
newWords.add(new ArrayList<String>());
loop(i);
}
这是循环方法。许多变量被声明为实例变量,因此我不必将它们传递给参数:
public static void loop(int level)
{
if (level == 0)
{
int pos = indices.size() - 1;
int pos2 = newWords.get(pos).size();
newWords.get(pos).add("");
for (Integer letIndex : indices)
{
String previous = newWords.get(pos).get(pos2);
newWords.get(pos).set(pos2, previous + lets.get(letIndex));
}
}
else
{
for (int i = 0; i < len; i++)
{
if (!indices.contains(i))
{
int indicesIndex = indices.size();
indices.add((Integer) i);
loop(level - 1);
indices.remove(indicesIndex);
}
}
}
}