在 Google 的 45 分钟技术面试中,我被问到一个 Leaper Graph 问题。我编写了工作代码,但后来因为缺乏数据结构知识而被拒绝了工作机会。我想知道我本可以做得更好。
问题如下:“给定一个 N 大小的棋盘,并告诉棋子可以水平跳 i 个位置(左或右)和垂直跳 j 个位置(上或下)(即,有点像国际象棋中的一匹马),可以跳投者能到达棋盘上的每一个位置吗?”
我写了以下算法。它通过标记图上所有被访问的点来递归地确定棋盘上的每个位置是否都可以到达。如果它不可达,那么至少有一个字段为假,该函数将返回假。
static boolean reachable(int i, int j, int n) {
boolean grid[][] = new boolean[n][n];
reachableHelper(0, 0, grid, i, j, n - 1);
for (int x = 0; x < n; x++) {
for (int y = 0; y < n; y++) {
if (!grid[x][y]) {
return false;
}
}
}
return true;
}
static void reachableHelper(int x, int y, boolean[][] grid, int i, int j, int max) {
if (x > max || y > max || x < 0 || y < 0 || grid[x][y]) {
return;
}
grid[x][y] = true;
int i2 = i;
int j2 = j;
for (int a = 0; a < 2; a++) {
for (int b = 0; b < 2; b++) {
reachableHelper(x + i2, y + j2, grid, i, j, max);
reachableHelper(x + j2, y + i2, grid, i, j, max);
i2 = -i2;
}
j2 = -j2;
}
}
现在,后来有人指出,最佳解决方案是实施 Donald Knuth 的 co-prime 实施: http ://arxiv.org/pdf/math/9411240v1.pdf 这是一个应该能够弄清楚的事情吗? 45分钟的技术面试??
除了上述之外,还有什么我可以做得更好的吗?
编辑:
-我询问了起始位置。有人告诉我从 0,0 开始就可以了。
edit2 根据反馈,我写了一个带有队列方法的while循环。当 n = 85 时,递归方法会遇到堆栈溢出。但是,使用下面的队列方法的 while 循环可以达到 ~n = 30,000。(之后它会遇到内存超过 GB 的堆问题)。如果您知道如何进一步优化,请告诉我。
static boolean isReachableLoop(int i, int j, int n) {
boolean [][] grid = new boolean [n][n];
LinkedList<Point> queue = new LinkedList<Point>();
queue.add(new Point(0,0)); // starting position.
int nodesVisited = 0;
while (queue.size() != 0) {
Point pos = queue.removeFirst();
if (pos.x >= 0 && pos.y >= 0 && pos.x < n && pos.y < n) {
if (!grid[pos.x][pos.y]) {
grid[pos.x][pos.y] = true;
nodesVisited++;
int i2 = i;
int j2 = j;
for (int a = 0; a < 2; a++) {
for (int b = 0; b < 2; b++) {
queue.add(new Point(pos.x+i2, pos.y+j2));
queue.add(new Point(pos.x+j2, pos.y+i2));
i2 = -i2;
}
j2 = -j2;
}
}
}
}
if (nodesVisited == (n * n)) {
return true;
} else {
return false;
}
}