This is a graph problem, and the problem try to find the shortest path. So BFS is just right solution, the following is my first solution.
It works but TLE. Why? Because I tried to search path from all four quadrants.
The time complexity is O(max(|x|, |y|)2.
public int minKnightMoves(int x, int y) { Set<String> visited = new HashSet<>(); int[][] dirs = {{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1},{-2,1},{-1,2}}; Queue<int[]> queue = new LinkedList<>(); queue.offer(new int[]{0,0}); visited.add("0,0"); int steps = 0; while(!queue.isEmpty()){ int size = queue.size(); for(int i=0;i<size;i++){ int[] sqr = queue.poll(); if(sqr[0]==x && sqr[1]==y){ return steps; } for(int[] dir: dirs){ int nextX = dir[0]+sqr[0]; int nextY = dir[1]+sqr[1]; if(nextX>300 || nextX<-300 || nextY>300 || nextY<-300) continue; String temp = nextX+","+nextY; if(visited.contains(temp)) continue; queue.offer(new int[]{nextX, nextY}); visited.add(temp); } } steps++; } return steps; }
Since the most part of the shortest path should be within the same quadrant of the (x,y), we can have the following solution.
This soltuion can beat about 20%
public int minKnightMoves(int x, int y) { x = Math.abs(x); //within one quadrant y = Math.abs(y); Set<String> visited = new HashSet<>(); int[][] dirs = {{1, 2}, {2, 1}, {2, -1}, {1, -2}, {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2}}; Queue<int[]> queue = new LinkedList<>(); queue.offer(new int[]{0, 0}); visited.add("0,0"); int steps = 0; while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { int[] sqr = queue.poll(); if (sqr[0] == x && sqr[1] == y) { return steps; } for (int[] dir : dirs) { int nextX = dir[0] + sqr[0]; int nextY = dir[1] + sqr[1]; if (nextX < -1 || nextY < -1) //if x=1, y=1, either nextX or nextY need to be -1 continue; String temp = nextX + "," + nextY; if (visited.contains(temp)) continue; queue.offer(new int[]{nextX, nextY}); visited.add(temp); } } steps++; } return steps; }
Because we use String Type to tell visited, it is slow and occupy lot of memories.
We can have the following solution, using boolean[][] to tell visited which beat about 80%
public int minKnightMoves(int x, int y) { x = Math.abs(x); y = Math.abs(y); boolean[][] visited = new boolean[302][302]; int[][] dirs = {{1, 2}, {2, 1}, {2, -1}, {1, -2}, {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2}}; Queue<int[]> queue = new LinkedList<>(); queue.offer(new int[]{0, 0}); visited[1][1] = true; int steps = 0; while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { int[] sqr = queue.poll(); if (sqr[0] == x && sqr[1] == y) { return steps; } for (int[] dir : dirs) { int nextX = dir[0] + sqr[0]; int nextY = dir[1] + sqr[1]; if (nextX < -1 || nextY < -1 || nextX > 300 || nextY > 300) //if x=1, y=1, either nextX or nextY need to be -1 continue; if (visited[nextX + 1][nextY + 1]) continue; queue.offer(new int[]{nextX, nextY}); visited[nextX + 1][nextY + 1] = true; } } steps++; } return steps; }