主要思路:为避免递归函数的参数、状态积压在栈上,最终耗尽栈空间,参考了cps变换实现的思路。网上给出的cps尾调用,尾递归形成的链式函数,实质上就是返回部分结果和下一循环要执行的方法,个人感觉在阅读性和抽象能力不够友好,所以,改为记录部分结果,以及下一循环的节点值。
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.LinkedList;
public class MethodUtil {
private static class Entry<P, V> {
LinkedList<P> nodeList = new LinkedList<>();
V tempValue = null;
}
public static <P, V> V cps(P original, INodeManager<P, V> nv) {
Entry<P, V> entry = new Entry<>();
entry.tempValue = nv.addNodeValue(original, entry.tempValue);
nv.addChildNode(original, entry.nodeList);
while (entry.nodeList.size() > 0) {
P n = entry.nodeList.pollFirst();
entry.tempValue = nv.addNodeValue(n, entry.tempValue);
nv.addChildNode(n, entry.nodeList);
}
return entry.tempValue;
}
public interface INodeManager<P, V> {
@Nullable
V addNodeValue(@Nullable P node, @Nullable V value);
void addChildNode(@Nullable P node, @NonNull LinkedList<P> nodeList);
}
}
使用示例:
爬楼梯问题:可以一次上1级台阶,也可以一次上2级台阶,所以当只有1级台阶时有1种爬楼梯方式,当只有2级台阶时有2种爬楼梯方式;即有f(1)=1,f(2)=2。问当有n级台阶时有多少种爬楼梯方式?
这是一道经典当动态规划算法题,由于最后一步可能是上了1级台阶,也可能是上了2级台阶,所以有f(n)=f(n-1)+f(n-2);
常规解法:
public int step(int count) {
if (count == 1) {
return 1;
} else if (count == 2) {
return 2;
} else {
return step(count - 1) + step(count - 2);
}
}
使用上面当转换来做:
public int step(int index) {
Integer result = MethodUtil.cps(index, new INodeManager<Integer, Integer>() {
@Override
public Integer addNodeValue(Integer node, Integer value) {
if (node == null) {
return value;
} else if (node == 1) {
if (value == null) {
return 1;
} else {
return value + 1;
}
} else if (node == 2) {
if (value == null) {
return 2;
} else {
return value + 2;
}
}
return value;
}
@Override
public void addChildNode(Integer node, LinkedList<Integer> nodeList) {
if (node != null && node > 2) {
nodeList.add(node - 1);
nodeList.add(node - 2);
}
}
});
return result == null ? 0 : result;
}
此方法虽然避免了使用递归,但是需要创建许多的LinkedList中的Node对象,也是一笔不小的开销,目前没想到太好的解决方法。
2020-06-30
网友评论