1. 程式人生 > 實用技巧 >【LeetCode/LintCode】 題解丨網易面試題:騎士的最短路線

【LeetCode/LintCode】 題解丨網易面試題:騎士的最短路線

給定騎士在棋盤上的 ​初始​ 位置(一個2進位制矩陣 ​0​ 表示空 ​1​ 表示有障礙物),找到到達 ​終點​ 的最短路線,返回路線的長度。如果騎士不能到達則返回 ​-1​ 。

  • 起點跟終點必定為空.
  • 騎士不能碰到障礙物.
  • 路徑長度指騎士走的步數.

線上評測地址:

LintCode 領釦

說明

如果騎士的位置為(x,y),他下一步可以到達以下這些位置:

(x + 1, y + 2)
(x + 1, y - 2)
(x - 1, y + 2)
(x - 1, y - 2)
(x + 2, y + 1)
(x + 2, y - 1)
(x - 2, y + 1)
(x - 2, y - 1)

樣例

例1:

輸入:
[[0,0,0],
 [0,0,0],
 [0,0,0]]
source = [2, 0] destination = [2, 2] 
輸出: 2
解釋:
[2,0]->[0,1]->[2,2]

例2:

輸入:
[[0,1,0],
 [0,0,1],
 [0,0,0]]
source = [2, 0] destination = [2, 2] 
輸出:-1

演算法:BFS

樸素​BFS​搜搜最短路,BFS概括來說就是像雷達一樣,一層一層進行尋找目標點。當找到目標點後進行回溯。從而找到最佳路徑。也就是說每走一步都要找到到達該點的最短的路徑,最終得到到達所有點的最短路徑,這題每一次的下一步做了規定,按照日字形跳到下一步。

  • 根據下一跳位置建立方向陣列
  • ​dx=[1, 1, 2, 2, -1, -1, -2, -2]​
  • ​dy=[2, -2, 1, -1, 2, -2, 1, -1]​
  • 遍歷八個方向,進行搜尋
  • 用​grid​陣列標註是否訪問過某點
  • 注意判斷下一跳的位置是否越界

複雜度分析

  • 時間複雜度​O(n*m)​
    • 最多跑一邊圖 n為圖的行數,m為圖的列數,最多跑一邊圖,即n*m
  • 空間複雜度​O(n*m)​
    • 所有點的資訊 n為圖的行數,m為圖的列數
public class Solution {
    /**
     * @param grid: a chessboard included 0 (false) and 1 (true)
     * @param source: a point
     * @param destination: a point
     * @return: the shortest path 
     */
    public int shortestPath(boolean[][] grid, Point source, Point destination) {
        int n = grid.length,m = grid[0].length;
        if (n == 0 || m == 0) {
            return -1;
        }
        
        int[] dx = {1, 1, 2, 2, -1, -1, -2, -2};
        int[] dy = {2, -2, 1, -1, 2, -2, 1, -1};
        Queue<Point> queue = new LinkedList<>();
        queue.offer(source);
        grid[source.x][source.y] = true;
        int ans = 0;
        
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int k = 0; k < size; k++) {
                Point cur = queue.poll();
                //到達終點,返回距離
                if (cur.x == destination.x && cur.y == destination.y)  {
                    return ans;
                }
                for (int i = 0; i < 8; i++) {
                    Point next = new Point (
                        cur.x + dx[i],
                        cur.y + dy[i]
                    );
                    //判斷下一條可否到達
                    if (is_in_bound(next,n,m) && grid[next.x][next.y] == false) {
                        queue.offer(next);
                        grid[next.x][next.y] = true;
                    }
                }
            }
            ans++;
        }
        return -1;
    }
    //判斷是否越界
    private boolean is_in_bound(Point next,int n,int m) {
        return 0 <= next.x && next.x < n && 0 <= next.y && next.y < m;
    }
}

更多題解參考:九章演算法官網