publicintshortestPathBinaryMatrix(int[][] grid) {if (grid ==null||grid.length==0|| grid[0].length==0) {return-1; }int n =grid.length;if (grid[0][0] !=0|| grid[n -1][n -1] !=0) {return-1; }boolean[][] visited =newboolean[n][n];Queue<Integer> queue =newLinkedList<>();queue.offer(0); visited[0][0] =true;int[] x = {0,0,-1,1,1,-1,-1,1};int[] y = {-1,1,0,0,1,-1,1,-1};int level =1;int result =-1;while (!queue.isEmpty()) {int size =queue.size();for (int i =0; i < size; i++) {int cur =queue.poll();int curi = cur / n;int curj = cur % n;if (curi == n -1&& curj == n -1) {return level; }for (int k =0; k <8; k++) {int nexti = curi + x[k];int nextj = curj + y[k];if (inBound(nexti, nextj, n)&&!visited[nexti][nextj] && grid[nexti][nextj] ==0) {queue.offer(nexti * n + nextj); visited[nexti][nextj] =true; } } } level++; }return result;}privatebooleaninBound(int i,int j,int n) {if (i <0|| j <0|| i >= n || j >= n) {returnfalse; } else {returntrue; }}// 贴一个A*,T:O(nlogn),因为heap。S:O(n)classSolution {// Candidate represents a possible option for travelling to the cell// at (row, col).classCandidate {publicint row;publicint col;publicint distanceSoFar;publicint totalEstimate;publicCandidate(int row,int col,int distanceSoFar,int totalEstimate) {this.row= row;this.col= col;this.distanceSoFar= distanceSoFar;this.totalEstimate= totalEstimate; } }privatestaticfinalint[][] directions =newint[][]{{-1,-1}, {-1,0}, {-1,1}, {0,-1}, {0,1}, {1,-1}, {1,0}, {1,1}};publicintshortestPathBinaryMatrix(int[][] grid) {// Firstly, we need to check that the start and target cells are open.if (grid[0][0] !=0|| grid[grid.length-1][grid[0].length-1] !=0) {return-1; }// Set up the A* search.Queue<Candidate> pq =newPriorityQueue<>((a,b) ->a.totalEstimate-b.totalEstimate);pq.add(newCandidate(0,0,1, estimate(0,0, grid)));boolean[][] visited =newboolean[grid.length][grid[0].length];// Carry out the A* search.while (!pq.isEmpty()) {Candidate best =pq.remove();// Is this for the target cell?if (best.row==grid.length-1&&best.col== grid[0].length-1) {returnbest.distanceSoFar; }// Have we already found the best path to this cell?if (visited[best.row][best.col]) {continue; } visited[best.row][best.col] =true;for (int[] neighbour :getNeighbours(best.row,best.col, grid)) {int neighbourRow = neighbour[0];int neighbourCol = neighbour[1];// This check isn't necessary for correctness, but it greatly// improves performance.if (visited[neighbourRow][neighbourCol]) {continue; }// Otherwise, we need to create a Candidate object for the option// of going to neighbor through the current cell.int newDistance =best.distanceSoFar+1;int totalEstimate = newDistance +estimate(neighbourRow, neighbourCol, grid);Candidate candidate =newCandidate(neighbourRow, neighbourCol, newDistance, totalEstimate);pq.add(candidate); } }// The target was unreachable.return-1; }privateList<int[]> getNeighbours(int row,int col,int[][] grid) {List<int[]> neighbours =newArrayList<>();for (int i =0; i <directions.length; i++) {int newRow = row + directions[i][0];int newCol = col + directions[i][1];if (newRow <0|| newCol <0|| newRow >=grid.length|| newCol >= grid[0].length|| grid[newRow][newCol] !=0) {continue; }neighbours.add(newint[]{newRow, newCol}); }return neighbours; }// Get the best case estimate of how much further it is to the bottom-right cell.privateintestimate(int row,int col,int[][] grid) {int remainingRows =grid.length- row -1;int remainingCols = grid[0].length- col -1;returnMath.max(remainingRows, remainingCols); }}