1. 问题
阿里笔试第二题
给你一个迷宫,包括一个起点‘S’和一个终点‘E’,‘#’表示障碍,不可到达的位置,‘.'表示可以到达的位置,另外你可以跳跃,跳跃的规则是从一个点跳到该点在迷踪的中心对称的那个点上,最多跳跃5次,求从起点到达终点的最短路径长度。
2. 解决方法
BFS思路,就是遍历四个方向加跳跃(记住跳跃的次数),遍历过的加入到visited;如果不是障碍加到候选队列;直到找到终点或者遍历完。
import java.util.*;
class Migong{
static class Node{
int row;
int col;
int jumpCount;
int pathLen;
Node (int row, int col, int jumpCount, int pathLen){
this.row = row;
this.col = col;
this.jumpCount = jumpCount;
this.pathLen = pathLen;
}
}
public static int shortestPath(char[][] grid, int k){
int m = grid.length;
int n = grid[0].length;
LinkedList<Node> queue = new LinkedList<>();
// get start
boolean found = false;
int startX = 0;
int startY = 0;
for(int i=0;i<m;i++) {
for(int j=0;j<n;j++) {
if(grid[i][j] == 'S') {
startX = i;
startY = j;
found = true;
break;
}
}
if(found) break;
}
Node rootNode = new Node(startX,startY,0,0);
queue.add(rootNode);
Node[][] visited = new Node[m][n];
visited[0][0] = rootNode;
int dx[] = new int[]{-1,1,0,0};
int dy[] = new int[]{0,0,1,-1};
while(!queue.isEmpty()){
int count = queue.size();
while(count-->0){
Node tmp = queue.poll();
int row = tmp.row;
int col = tmp.col;
int jumpCount = tmp.jumpCount;
int pathLen = tmp.pathLen;
if(grid[row][col] == 'E'){
return pathLen;
}
//four directions
for(int i = 0;i < 4;i++){
int newRow = row + dx[i];
int newCol = col + dy[i];
if(newRow<0 || newRow>=m || newCol<0 || newCol>=n ){
continue;
}
if(jumpCount > k){
continue;
}
boolean addNode = false;
int newPathLen = -1;
if(grid[row][col] != '#') {
newPathLen = pathLen+1;
addNode = true;
}
Node newNode = new Node(newRow, newCol, jumpCount,newPathLen);
if(addNode) queue.add(newNode);
if(visited[newRow][newCol] == null){
visited[newRow][newCol] = newNode;
}
}
// jump
int newRow = m - 1-row;
int newCol = n - 1-col;
if(newRow<0 || newRow>=m || newCol<0 || newCol>=n || jumpCount>5){
;
}
else {
boolean addNode = false;
int newPathLen = -1;
if(grid[row][col] != '#') {
newPathLen = pathLen+1;
addNode = true;
}
Node newNode = new Node(newRow, newCol, jumpCount+1,newPathLen);
if(addNode) queue.add(newNode);
if(visited[newRow][newCol] == null|| jumpCount+1<visited[newRow][newCol].jumpCount){
visited[newRow][newCol] = newNode;
}
}
}
}
return -1;
}
public static void main(String[] args){
char[][] grid = {{'#', 'S', '.', '.','.'},
{'E', '#', '#', '.','.'},
{'#', '#', '#', '.','.'},
{'#', '#', '#', '.','.'}};
int result = shortestPath(grid,5);
System.out.println(result);
}
}
python 代码:
import collections
from typing import List
class Solution:
def shortestPath(self, grid: List[List[int]], k: int) -> int:
m, n = len(grid), len(grid[0])
if m == 1 and n == 1:
return 0
# start point
found = False
sx = 0
sy = 0
for i in range(m):
for j in range(n):
if grid[i][j] == 'S':
sx = i
sy = j
found = True
break
if found:
break
visited = set([(sx, sy, k)])
q = collections.deque([(sx, sy, k)])
step = 0
while len(q) > 0:
step += 1
cnt = len(q)
for _ in range(cnt):
x, y, rest = q.popleft()
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
nx, ny = x + dx, y + dy
if 0 <= nx < m and 0 <= ny < n:
if grid[nx][ny] == 'E':
return step
if (nx, ny, rest) not in visited:
if grid[nx][ny] != '#':
q.append((nx, ny, rest))
visited.add((nx, ny, rest))
# jump
if rest>0:
nx, ny = m-1-x, n-1-y
if grid[nx][ny] == 'E':
return step
if (nx, ny, rest) not in visited:
if grid[nx][ny] != '#':
q.append((nx, ny, rest-1))
visited.add((nx, ny, rest-1))
return -1
solution = Solution()
grid = \
[['#', 'S', '.', '.'],\
['E', '#', '#', '.'],\
['#', '#', '#', '.'],\
['#', '#', '#', '.']]
k = 5
print(solution.shortestPath(grid,k))
参考: