我必须实现一个递归方法 merge(long[] arr, int i)
如果相邻元素具有相同的值,则从索引开始将其相乘 i
. 例子:
merge({1, 2, 2, 4}, 0)
应该生成如下数组:
{1, 4, 4}
如果一个数字有多个(n)次出现 {1, 2, 2, 2, 2, 5}
,所有这些必须相乘: {1, 16, 5}
.
已经合并的号码不能再合并 {1, 4, 4, 16} -> {1, 16, 16}
.
所有这些都必须通过只使用一个方法merge来实现,并且在原始数组中每个元素只有一个递归调用。
这是一个使用递归和循环的工作实现:
public static long[] merge(long[] ns, int i) {
final long[] EMPTY_LONG_ARRAY = {};
if (i < 0) {
return merge(ns, 0, m); // if i negative, start at 0
} else if (i >= ns.length) {
return EMPTY_LONG_ARRAY; // if out of bounds, return empty array
} else if (i == ns.length - 1) {
return ns; // base case
} else { // recursion in here
if (ns[i] == ns[i + 1]) { // if next long is equal
int occurences = 1; // first occurence
for (int j = i; j < ns.length - 1; j++) {
if (ns[j] == ns[j + 1])
occurences++;
else
break;
} // add next occurences
long[] newArray = new long[ns.length - occurences + 1]; // new array is (occurences-1) shorter
for (int j = 0; j < newArray.length; j++) { // fill new array
if (j < i) {
newArray[j] = ns[j]; // left of i: values stay the same
} else if (j > i) {
newArray[j] = ns[j + occurences - 1]; // pull values right of i (occurences-1) to the left
} else {
int counter = occurences;
long mergedValue = ns[j];
while (counter > 1) {
mergedValue *= ns[j];
counter--;
}
newArray[j] = mergedValue; // at j: value is ns[j]^occurences
}
}
if (i == ns.length - 1)
return merge(newArray, i, m);
else
return merge(newArray, i + 1, m); // if bounds permit it, jump to next number
} else {
return merge(ns, i + 1, m); // nothing to merge, go one step forward
}
}
这个实现产生正确的结果,但是递归深度是错误的(在原始数组ns[]中每个元素需要一个递归调用)。
我肯定有个天才可以用线性递归来解决这个问题。
1条答案
按热度按时间6tqwzwtp1#
让我们将循环转换为递归调用。这样做的唯一原因是作业要求它-它不是更具可读性(至少对我来说是这样),而且它实际上更慢。出于效率的考虑,人们通常希望转向另一个方向:从递归到循环。
首先,代码的注解版本:
首先,让我重写一下,提高效率。由于重复项只有在相邻时才被删除,因此不需要内部循环,可以编写以下内容:
假设这是可行的(注意-我还没有测试过),我现在将把它转换成尾部递归。将有两部分:驱动程序代码(不在循环中的所有内容)和递归代码(循环部分)。
一般的想法是将所有状态作为参数传递给递归函数,并在开始时检查循环终止,将循环代码放在中间,最后为下一次迭代进行递归调用。