好吧,如果你维护一个数组、一个列表或任何其他告诉你你在每个数组中的位置的东西,它可以在没有递归的情况下完成。
假设我们有一个这样的元素列表:
/**
* Class to contain an index and a length.
*/
private static class Pair {
private int currIndex = 0;
int length;
/**
* Constructor - we pass the length of the respective array.
* This does not change during the lifetime of this program.
* @param length The length of the respective array.
*/
public Pair( int length ) {
this.length = length;
}
/**
* Increment the index by one. If we reach the length, start
* from zero, and indicate that there is carry. That is, that
* the next element will need to be updated.
* @return True if next index down needs to be updated.
*/
public boolean updateAndCheckCarry() {
currIndex ++;
if ( currIndex >= length ) {
currIndex = 0;
return true;
}
return false;
}
/**
* Getter for the index itself
* @return The current index.
*/
public int getIndex() {
return currIndex;
}
}
我们的想法是遍历每个数组,比如{4, 5} 数组。我们从四个开始,因为我们将通过我们的循环,我们将更新到五个。但是随后上面的元素发生了变化,我们需要再次进入四个。这个类可以帮助我们做到这一点。
所以我们准备了我们的索引列表:
/**
* Prepare an index list, which for each element of the original list,
* will contain a current index and the limit. This allows us to keep
* track of which element we are in in every array.
*
* @param listToIndex
* @return The index list
*/
public static LinkedList<Pair> prepareIndexList(List<int[]> listToIndex) {
LinkedList<Pair> result = new LinkedList<>();
for ( int[] element : listToIndex ) {
Pair item = new Pair(element.length);
result.add(item);
}
return result;
}
这相当简单 - 我们只需遍历我们的列表并收集长度,以帮助我们稍后能够知道何时将每个索引归零。
在每次迭代中,我们应该遍历列表并打印每个数组当前索引中的数字。因此,如果我们的第一个数组的索引为 2,第二个为 1,最后一个为 0,我们将从您的示例中收集 4、5 和 1。
/**
* Get the current value to print from the list. That is, go through the
* list and collect the appropriate element from each array, into a string.
*
* @param valuesList The list of integer arrays to go through
* @param indexList The list of current indices
* @return String representing the collected current value.
*/
public static String getNextValue(List<int[]> valuesList, List<Pair> indexList) {
StringBuilder sb = new StringBuilder(valuesList.size());
Iterator<Pair> indexIter = indexList.iterator();
for ( int[] element : valuesList ) {
int index = indexIter.next().getIndex();
sb.append(element[index]);
}
return sb.toString();
}
现在,这个解决方案真正的“肉”是索引的更新。这很像一个数字加 1。想象一下,您有号码1958,然后将其加 1。变成1959。现在你再加 1。所以,9 变成了0,你需要把 1 带到 5。你现在有1960。保持这种状态,您将获得1999。此时,你加 1,将 9 归零,向左进位,然后也归零,向左进位,然后归零,向左进位,得到2000。
以同样的方式——当我们需要携带 1 时,从右边开始并通过左边——我们也更新我们的索引列表:
/**
* Update the index list. Starting from the end and going backwards, we
* increment each index. Each index is zeroed if it gets past the respective
* array size, and also returns true to indicate that the next level needs
* to be updated as well.
*
* @param indexList The list of indices to be updated
* @return true if the updates bubbled all the way to the first element,
* and it, too, was zeroed. This means we have completed printing
* the tree.
*/
public static boolean updateIndexList(LinkedList<Pair> indexList) {
Iterator<Pair> iter = indexList.descendingIterator();
boolean hasCarry = true;
while ( iter.hasNext() && hasCarry ) {
hasCarry = iter.next().updateAndCheckCarry();
}
return hasCarry;
}
如果我们从最左边的索引中“进位” - 属于我们原始列表头部的索引 - 这意味着我们已经完成了程序,因为我们已经遍历了第一个数组中的所有元素。发生这种情况时,上述方法返回 true。
现在我们只需要调用我们的方法:
LinkedList indexList = prepareIndexList(list);
boolean completed = false;
while ( ! completed ) {
System.out.println(getNextValue( list, indexList ));
completed = updateIndexList(indexList);
}