所以我现在正在制作一个游戏,其中指令是使用存储在标记索引处的整数(在这种情况下为圆形)在数组内向左或向右移动,直到我们可以将圆圈移到最后一个索引数组。数组的最后一个整数始终为0.
例如,
[4] 1 2 3 1 0,这里我们从圆0开始(索引)
我们向右移动4,1 1 2 3 [1] 0
然后1次向右,4 1 2 3 1 [0]。在这里游戏停止,我们赢了。
对于递归方法,我的代码如下:
public static boolean rightWing (int circle, int[] game, List<Integer> checkerList){
int last = game.length-1;
if (circle == last){ // base case for recursion
return true;
}
if (circle < 0){ // if we go out of bounds on the left
return false;
}
if (circle > last){ // if we go out of bounds on the right
return false;
}
if (checkerList.contains(circle)){ // check for the impossible case
return false;
}
checkerList.add(circle); // adds the circle value for the last check to checkerList so we can check for the impossible case
int moveRight = circle + game[circle]; // these two integers help the game move according to the value of the int at circle
int moveLeft = circle - game[circle];
return rightWing( moveRight, game, checkerList) || rightWing(moveLeft, game,checkerList);
}
这很好用,但唯一的问题是它的递归和缓慢。我试图使用循环和堆栈/队列重新设计它以使其更有效率,但是在写完这个之后我陷入困境(伪):
Boolean rightWing (int circle, List<int> game, List<int> checkerList)
Int lastPlace = game.size() - 1
For int i <- 0 to game.size() - 1 do
If i equals lastPlace then // returns true when i is at the last position of the game
Return true
有关如何前进的任何意见将不胜感激!
答案 0 :(得分:3)
最重要的一点:在缓慢调试应用时,您应首先收集一些效果数据,以确定您的应用在大部分时间内花费的时间。否则修复性能效率低下。您可以使用与{jdk捆绑在一起的jvisualvm
。
为什么它可能会变慢是因为:
if (checkerList.contains(circle)){ // check for the impossible case
return false;
}
列表中的项目越多,它就越慢。列表的linear complexity
方法为contains
。如果您使用constant complexity
,则可以HashSet
。例如。如果您有包含100个元素的列表,则此部分将使用List
比使用HashSet
慢100倍。
可能需要一些时间的另一件事是装箱/拆箱:每次将元素放入列表时,int
都被包装到新的Integer
对象中 - 这称为装箱。您可能希望使用IntSet
来避免装箱/取消装箱并节省GC时间。
我不希望这会影响您的申请速度,但仅仅是为了完整答案。
将递归应用程序转换为迭代形式非常简单:封面下的每个方法参数都会在您(或其他函数)的每次调用时存储在隐藏堆栈中。在转换过程中,您只需创建自己的堆栈并手动管理
public static boolean rightWingRecursive(int circle, int[] game) {
Set<Integer> checkerList = new HashSet<Integer>();
Deque<Integer> statesToExplore = new LinkedList<>();
int last = game.length - 1;
statesToExplore.push(circle);
while (!statesToExplore.isEmpty()) {
int circleState = statesToExplore.pop();
if (circleState == last) { // base case for recursion
return true;
}
if (circleState < 0) { // if we go out of bounds on the left
continue;
}
if (circleState > last) { // if we go out of bounds on the right
continue;
}
if (checkerList.contains(circle)) { // check for the impossible case
continue;
}
checkerList.add(circle); // adds the circle value for the last check to
// checkerList so we can check for the
// impossible case
int moveRight = circle + game[circle]; // these two integers help the
// game move according to the
// value of the int at circle
int moveLeft = circle - game[circle];
statesToExplore.push(moveRight);
statesToExplore.push(moveLeft);
}
return false;
}