题目
题解
看到最短路径,首先考虑BFS,不行再考虑DP!
广度优先搜索方法的正确性在于:我们一定不会到达同一个位置两次及以上,因为这样必定不是最少的移动次数。
假设当前蛇尾位置(x,y),选择蛇尾位置的好处是旋转操作时,无需进行坐标的转换。
将蛇尾坐标和蛇的水平/竖直状态一起形成一个三元组(x,y,status),其中status=0表示水平状态,1表示竖直状态。
当 status=0(蛇水平):
- 【右移】需要保证(x,y+2)是空的单元格;
- 【下移】需要保证(x+1,y) 和(x+1,y+1) 均是空的单元格;
- 【顺时针旋转】需要保证 (x+1,y) 和 (x+1,y+1) 均是空的单元格。
当 status=1(蛇竖直):
- 【右移】需要保证(x,y+1) 和(x+1,y+1) 均是空的单元格;
- 【下移】需要保证(x+2,y) 是空的单元格;
- 【逆时针旋转】需要保证(x,y+1) 和(x+1,y+1) 均是空的单元格;
用广度优先搜索解决本题。
class Solution {
public int minimumMoves(int[][] grid) {
int n=grid.length;
int[][][] dist=new int[n][n][2];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
Arrays.fill(dist[i][j],-1);
}
}
dist[0][0][0]=0;
Queue<int[]>queue=new ArrayDeque<>();
queue.offer(new int[]{0,0,0});
while(!queue.isEmpty()){
int[] point=queue.poll();
int x=point[0],y=point[1],status=point[2];//(x,y)为蛇尾坐标
//蛇水平
if(status==0){
//右移
if(y+2<n&&dist[x][y+1][0]==-1&&grid[x][y+2]==0){
dist[x][y+1][0]=dist[x][y][0]+1;
queue.offer(new int[]{x,y+1,0});
}
//下移
if(x+1<n&&dist[x+1][y][0]==-1&&grid[x+1][y]==0&&grid[x+1][y+1]==0){
dist[x+1][y][0]=dist[x][y][0]+1;
queue.offer(new int[]{x+1,y,0});
}
//顺时针旋转
if(x+1<n&&y+1<n&&dist[x][y][1]==-1&&grid[x+1][y]==0&&grid[x+1][y+1]==0){
dist[x][y][1]=dist[x][y][0]+1;
queue.offer(new int[]{x,y,1});
}
}
//蛇竖直
else{
//右移
if(y+1<n&&dist[x][y+1][1]==-1&&grid[x][y+1]==0&&grid[x+1][y+1]==0){
dist[x][y+1][1]=dist[x][y][1]+1;
queue.offer(new int[]{x,y+1,1});
}
//下移
if(x+2<n&&dist[x+1][y][1]==-1&&grid[x+2][y]==0){
dist[x+1][y][1]=dist[x][y][1]+1;
queue.offer(new int[]{x+1,y,1});
}
//逆时针旋转
if(x+1<n&&y+1<n&&dist[x][y][0]==-1&&grid[x][y+1]==0&&grid[x+1][y+1]==0){
dist[x][y][0]=dist[x][y][1]+1;
queue.offer(new int[]{x,y,0});
}
}
}
return dist[n-1][n-2][0];
}
}
时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( n 2 ) O(n^2) O(n2)