所以我一直在研究一个问题,基本前提是给定一个任意大小的网格,我需要计算“游览”的数量。游览是从左上角开始的运行(我使用点x = 1,y = 1表示)并且在左下角结束(x = 1 y = max,无论'y'的最大值是)。除此之外,它必须触及沿途的每个其他点,并且只能访问网格中的任何一点。
我在下面写的方式,它在~42-45秒内运行,但如果可能的话,我想让它在30秒或更短的时间内运行。那么,我的问题是,我可以改变或取出哪些能使它更快地运行?
我已经尝试将所有内容都设置为静态并实例化该类(这为我的运行时间增加了几秒)。
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.Date;
public class CodingPuzzle
{
public static List<Point> lAllPoints = new ArrayList<Point>();
public static int iMaxX;
public static int iMaxY;
public static int iCompletePaths = 0;
public static void depthFirstSearch(Point current, Stack<Point> result)
{
if (result.contains(current))
return;
result.push(current);
if (current.x == 1 && current.y == iMaxY && result.size() == iMaxX*iMaxY)
{
// This is a complete path
iCompletePaths++;
}
for (Point p: getPossibleMoves(current))
{
depthFirstSearch(p, result);
}
// No path was found
result.pop();
return;
}
public static List<Point> getPossibleMoves (Point fromPoint)
{
int iCurrentPointIndex = lAllPoints.indexOf(fromPoint);
List<Point> lPossibleMoves = new ArrayList<Point>();
if (fromPoint.x == 1 && fromPoint.y == 1)
{
// Top left point
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex + 1));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex + iMaxY));
}
else if (fromPoint.x == 1 && fromPoint.y == iMaxY)
{
// Bottom left point. Should always be the last point. No valid moves.
// If a path gets here before the end it shouldn't need to continue.
}
else if (fromPoint.x == iMaxX && fromPoint.y == 1)
{
// Top right point
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex - iMaxY));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex + 1));
}
else if (fromPoint.x == iMaxX && fromPoint.y == iMaxY)
{
// Bottom right point
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex - iMaxY));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex - 1));
}
else if (fromPoint.x == 1 && fromPoint.y != iMaxY)
{
// Any other point on the left side
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex - 1));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex + 1));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex + iMaxY));
}
else if (fromPoint.x == iMaxX)
{
// Any other point on the right side
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex - 1));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex + 1));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex - iMaxY));
}
else if (fromPoint.y == 1)
{
// Any other point on the top
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex + 1));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex - iMaxY));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex + iMaxY));
}
else if (fromPoint.y == iMaxY && fromPoint.x != 1)
{
// Any other point on the bottom
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex - 1));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex - iMaxY));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex + iMaxY));
}
else
{
// Any other point not on an edge.
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex + 1));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex - 1));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex - iMaxY));
lPossibleMoves.add(lAllPoints.get(iCurrentPointIndex + iMaxY));
}
return lPossibleMoves;
}
public static void setUpGrid(int x, int y)
{
iMaxX = x;
iMaxY = y;
for (int i = 1; i <= x; i++)
for (int j = 1; j <= y; j++)
lAllPoints.add(new Point(i, j));
}
public static void main(String[] args)
{
Date start = new Date(System.currentTimeMillis());
setUpGrid(10, 4);
Stack<Point> sCurrentPoints = new Stack<Point>();
depthFirstSearch(lAllPoints.get(0), sCurrentPoints);
Date end = new Date(System.currentTimeMillis());
long total = end.getTime() - start.getTime();
System.out.println(iCompletePaths + " paths found in " + total/1000 + " seconds.");
}
答案 0 :(得分:3)
我会减少代码为完成计数所做的工作量。
public class CodingPuzzle2 {
private final int width;
private final int height;
public CodingPuzzle2(int width, int height) {
this.width = width;
this.height = height;
}
public int countPaths(int x, int y) {
boolean[][] visited = new boolean[width][height];
int[] count = {0};
countPaths(x, y, visited, 1, count);
return count[0];
}
private void countPaths(int x, int y, boolean[][] visited, int depth, int[] count) {
if (x < 0 || x >= width || y < 0 || y >= height || visited[x][y])
return;
visited[x][y] = true;
try {
if (x == 0 && y == height - 1) {
if (depth == width * height)
count[0]++;
return;
}
countPaths(x, y + 1, visited, depth+1, count);
countPaths(x + 1, y, visited, depth+1, count);
countPaths(x - 1, y, visited, depth+1, count);
countPaths(x, y - 1, visited, depth+1, count);
} finally {
visited[x][y] = false;
}
}
public static void main(String... args) {
long start = System.nanoTime();
CodingPuzzle2 cp = new CodingPuzzle2(10,4);
int count = cp.countPaths(0, 0);
long time = System.nanoTime() - start;
System.out.printf("%,d paths found in %.3f seconds.%n", count, time / 1e9);
}
}
打印
2,329 paths found in 1.758 seconds.
答案 1 :(得分:0)
我要做的第一件事是描述你的代码(正如彼得在你的问题的评论中所说)。如果不知道你在哪里花时间,就很难“让事情变得更快”。但是你的算法可能效率低下。对于分析,您可以使用随JVM一起提供的jvisualvm。
您可能希望查看algorithms来解决图表的Hamiltonian Path,这实际上就是您正在做的事情。有比蛮力更有效的解决方案。
答案 2 :(得分:0)
别人怎么说。它将帮助您成为更好的程序员。
除此之外,这是您正在寻找的快速胜利 - 从Stack
切换到Deque,即ArrayDeque。这一次更改使我的Java 7 -server
计算机上的速度提高了44%。