Java 骑士最短路径测试案例在foobar中失败
我遇到了谷歌foobar问题的麻烦。我只有一个测试不及格。我想确定一个骑士在测试板上的点之间移动的最小移动次数。算法如下所示Java 骑士最短路径测试案例在foobar中失败,java,algorithm,Java,Algorithm,我遇到了谷歌foobar问题的麻烦。我只有一个测试不及格。我想确定一个骑士在测试板上的点之间移动的最小移动次数。算法如下所示 import java.lang.Math; public class Answer { public static int answer(int start, int end) { int[][] board = new int[8][8]; int[] startLocation = new int[2]; int[] end
import java.lang.Math;
public class Answer {
public static int answer(int start, int end) {
int[][] board = new int[8][8];
int[] startLocation = new int[2];
int[] endLocation = new int[2];
//chess board generated in nested loop
for (int j = 0; j < 8; j++) {
int[] row = new int[8];
for (int i = 0; i < 8; i++) {
row[i] = i + 8 * j;
}
board[j] = row;
}
//find locations of start and end points on board
for (int m = 0; m < 8; m++){
for (int n = 0; n < 8; n++){
if (board[m][n] == start) startLocation = new int[]{m,n};
if (board[m][n] == end) endLocation = new int[]{m,n};
}
}
int[] delta = new int[]{Math.abs(endLocation[0] - startLocation[0]),Math.abs(endLocation[1]-startLocation[1])};
if (delta[0] < delta[1]){
int temp = delta[0];
delta[0] = delta[1];
delta[1] = temp;
}
//generate double array of possible moves
if (delta[0] == 2 & delta[1] == 1) return 1;
if ((delta[0]+ delta[1] == 2) || (delta[0] == 3 && delta[1] == 1) ||
(delta[0] == 3 && delta[1] == 3) || (delta[0] == 4 && delta[1] == 2) || (delta[0] == 4 && delta[1] == 0)){
return 2;
}
if ((delta[0] == 1 && delta[1] == 0) || (delta[0] == 3 && delta[1] == 0) ||
(delta[0] == 5 && delta[1] == 0) || (delta[0] == 3 && delta[1] == 2) || (delta[0] == 4 && delta[1] == 3)
|| (delta[0] == 4 && delta[1] == 1) || (delta[0] == 6 && delta[1] == 1) || (delta[0] == 6 && delta[1] == 3)
|| (delta[0] == 5 && delta[1] == 2) || (delta[0] == 5 && delta[1] == 4)){
return 3;
}
if ((delta[0] == 6 && delta[1] == 0) || (delta[0] == 2 && delta[1] == 2) ||
(delta[0] == 5 && delta[1] == 1) || (delta[0] == 7 && delta[1] == 1) || (delta[0] == 6 && delta[1] == 2)
|| (delta[0] == 7 && delta[1] == 5) || (delta[0] == 7 && delta[1] == 3) || (delta[0] == 5 && delta[1] == 3)
|| (delta[0] == 4 && delta[1] == 4) || (delta[0] == 5 && delta[1] == 5) || (delta[0] == 6 && delta[1] == 6)
|| (delta[0] == 6 && delta[1] == 4)){
return 4;
}
if ((delta[0] == 7 && (delta[1] == 0 || delta[1] == 2 || delta[1] == 4 || delta[1] == 6)) || (delta[0] == 6 && delta[1] == 5)){
return 5;
}
return 6;
}
}
import java.lang.Math;
公共类答案{
公共静态整数应答(整数开始,整数结束){
int[][]板=新int[8][8];
int[]位=新的int[2];
int[]endLocation=新的int[2];
//嵌套循环生成的棋盘
对于(int j=0;j<8;j++){
int[]行=新int[8];
对于(int i=0;i<8;i++){
行[i]=i+8*j;
}
board[j]=行;
}
//查找板上起点和终点的位置
对于(int m=0;m<8;m++){
对于(int n=0;n<8;n++){
if(board[m][n]==start)startLocation=newint[]{m,n};
如果(board[m][n]==end)endLocation=newint[]{m,n};
}
}
int[]delta=newint[]{Math.abs(endLocation[0]-startLocation[0]),Math.abs(endLocation[1]-startLocation[1]);
if(增量[0]<增量[1]){
内部温度=增量[0];
δ[0]=δ[1];
δ[1]=温度;
}
//生成可能移动的双数组
if(delta[0]==2&delta[1]==1)返回1;
如果((δ[0]+δ[1]==2)| |(δ[0]==3&&δ[1]==1)| |
(δ[0]==3和δ[1]==3)| |(δ[0]==4和δ[1]==2)| |(δ[0]==4和δ[1]==0)){
返回2;
}
如果((δ[0]==1&&δ[1]==0)| |(δ[0]==3&&δ[1]==0)| |
(δ[0]==5和δ[1]==0)| |(δ[0]==3和δ[1]==2)| |(δ[0]==4和δ[1]==3)
||(δ[0]==4和δ[1]==1)| |(δ[0]==6和δ[1]==1)| |(δ[0]==6和δ[1]==3)
||(δ[0]==5&&δ[1]==2)| |(δ[0]==5&&δ[1]==4)){
返回3;
}
如果((δ[0]==6&&δ[1]==0)| |(δ[0]==2&&δ[1]==2)||
(δ[0]==5和δ[1]==1)| |(δ[0]==7和δ[1]==1)| |(δ[0]==6和δ[1]==2)
||(δ[0]==7和δ[1]==5)| |(δ[0]==7和δ[1]==3)| |(δ[0]==5和δ[1]==3)
||(δ[0]==4和δ[1]==4)| |(δ[0]==5和δ[1]==5)| |(δ[0]==6和δ[1]==6)
||(增量[0]==6和增量[1]==4)){
返回4;
}
如果((δ[0]==7&&(δ[1]==0 | |δ[1]==2 | | |δ[1]==4 | | |δ[1]==6&&δ[1]==5)){
返回5;
}
返回6;
}
}
在什么情况下此代码会失败?如果开始是
0,0
,结束是1,1
,您的答案是2
移动,但这需要在棋盘外着陆。当然,其他三个角也是这样
更新 为了好玩,我决定编写代码来找到最短的路径(无论如何是其中一条),并打印所采用的路径 代码 输出
2:2,2->4,1->3,3
+---------------+
| |
| 1 |
| 0 |
| 2 |
| |
| |
| |
| |
+---------------+
4:0,0->2,1->0,2->2,3->1,1
+---------------+
|0 |
| 4 1 |
|2 |
| 3 |
| |
| |
| |
| |
+---------------+
6:0,0->2,1->3,3->5,4->7,5->5,6->7,7
+---------------+
|0 |
| 1 |
| |
| 2 |
| 3 |
| 4|
| 5 |
| 6|
+---------------+
5:0,0->1,2->3,3->5,4->7,5->6,7
+---------------+
|0 |
| |
| 1 |
| 2 |
| 3 |
| 4|
| |
| 5 |
+---------------+
6:7,7->6,5->4,4->3,2->2,0->1,2->0,0
+---------------+
|6 4 |
| |
| 5 3 |
| |
| 2 |
| 1 |
| |
| 0|
+---------------+
我没有考虑的测试用例是当“开始在结束”位置为一且相同时。这是解决方案中缺少的一部分…欢迎使用堆栈溢出。这不是调试服务。你应该自己提出一些测试用例。您甚至可以编写一个测试程序来生成所有64*64可能的输入。看看那些你最难用手解决的问题…然后用手解决它们,看看它们是否与你的算法的输出相匹配。注意,如果你考虑到棋盘的所有对称性,你可以显著减少可能的输入数量。例如,从左上角移动到右上角是从左下角移动到右下角的镜像。因此,两种情况下所需的移动次数将完全相同。事实上,您可以在测试中使用它来确保两种情况下得到相同的答案。如果您没有,那么您知道您的代码有问题。不幸的是,如果你得到了相同的答案,那么它不会告诉你太多。你基本上预先计算了所有可能的情况。“很可能你在其中一个问题上犯了错误。”代码学徒,注释的作者。我已经考虑到对称性,并手工求解了几对……我将尝试求解更多……我建议您开发一种算法来计算所需的移动次数,而不是将解编码为一组if语句。用算法解决问题是计算机程序员最重要的技能之一。代码基于相对定位。起点是
class Path {
private final int x;
private final int y;
private final int moveNo;
private final Path prev;
private Path(int x, int y, int moveNo, Path prev) {
this.x = x;
this.y = y;
this.moveNo = moveNo;
this.prev = prev;
}
public static Path startAt(int x, int y) {
if (x < 0 || x >= 8 || y < 0 || y >= 8)
throw new IllegalArgumentException("Invalid position: " + x + "," + y);
return new Path(x, y, 0, null);
}
public Path move(Move move) {
int newX = this.x + move.getX();
int newY = this.y + move.getY();
if (newX < 0 || newX >= 8 || newY < 0 || newY >= 8)
return null; // Outside board
for (Path step = this.prev; step != null; step = step.prev)
if (step.x == newX && step.y == newY)
return null; // Backstep
return new Path(newX, newY, this.moveNo + 1, this);
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public int getNumberOfMoves() {
return this.moveNo;
}
@Override
public String toString() {
if (this.prev == null)
return this.x + "," + this.y;
return this.prev + " -> " + this.x + "," + this.y;
}
public void printBoard() {
char[][] board = new char[8][15];
for (char[] row : board)
Arrays.fill(row, ' ');
for (Path step = this; step != null; step = step.prev)
board[step.y][step.x * 2] = Character.forDigit(step.moveNo, 36);
System.out.println(" +---------------+");
for (char[] row : board)
System.out.println(" |" + new String(row) + "|");
System.out.println(" +---------------+");
}
}
class Move {
private static final Move[] KNIGHT_MOVES = {
new Move(-1, -2), new Move( 1, -2),
new Move( 2, -1), new Move( 2, 1),
new Move( 1, 2), new Move(-1, 2),
new Move(-2, 1), new Move(-2, -1) };
private final int x;
private final int y;
public Move(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public static Path find(int startX, int startY, int endX, int endY) {
final Comparator<Path> distanceComparator = new Comparator<Path>() {
@Override
public int compare(Path step1, Path step2) {
int dx1 = step1.getX() - endX, dy1 = step1.getY() - endY;
int dx2 = step2.getX() - endX, dy2 = step2.getY() - endY;
return Integer.compare(dx1 * dx1 + dy1 * dy1, dx2 * dx2 + dy2 * dy2);
}
};
Queue<Path> queue = new ArrayDeque<>();
queue.add(Path.startAt(startX, startY));
for (Path step; (step = queue.poll()) != null; ) {
List<Path> nextSteps = new ArrayList<>();
for (Move move : KNIGHT_MOVES) {
Path newStep = step.move(move);
if (newStep != null) {
if (newStep.getX() == endX && newStep.getY() == endY)
return newStep;
nextSteps.add(newStep);
}
}
Collections.sort(nextSteps, distanceComparator);
queue.addAll(nextSteps);
}
return null;
}
}
public static void main(String[] args) {
test(2,2, 3,3);
test(0,0, 1,1);
test(0,0, 7,7);
test(0,0, 6,7);
test(7,7, 0,0);
}
private static void test(int startX, int startY, int endX, int endY) {
Path step = Move.find(startX, startY, endX, endY);
System.out.println(step.getNumberOfMoves() + ": " + step.toString());
step.printBoard();
}