zoukankan      html  css  js  c++  java
  • [LeetCode] 1197. Minimum Knight Moves

    In an infinite chess board with coordinates from -infinity to +infinity, you have a knight at square [0, 0].

    A knight has 8 possible moves it can make, as illustrated below. Each move is two squares in a cardinal direction, then one square in an orthogonal direction.

    Return the minimum number of steps needed to move the knight to the square [x, y].  It is guaranteed the answer exists.

    Example 1:

    Input: x = 2, y = 1
    Output: 1
    Explanation: [0, 0] → [2, 1]
    

    Example 2:

    Input: x = 5, y = 5
    Output: 4
    Explanation: [0, 0] → [2, 1] → [4, 2] → [3, 4] → [5, 5] 

    Constraints:

    • |x| + |y| <= 300

    进击的骑士。一个坐标可以从 -infinity 延伸到 +infinity 的 无限大的 棋盘上,你的 骑士 驻扎在坐标为 [0, 0] 的方格里。骑士的走法和中国象棋中的马相似,走 “日” 字:即先向左(或右)走 1 格,再向上(或下)走 2 格;或先向左(或右)走 2 格,再向上(或下)走 1 格。每次移动,他都可以按图示八个方向之一前进。现在,骑士需要前去征服坐标为 [x, y] 的部落,请你为他规划路线。最后返回所需的最小移动次数即可。本题确保答案是一定存在的。

    国际象棋的规则跟中国象棋类似,都是马走日。这个题基本上就是在问你,你现在有一个马在[0, 0],问你最少需要走几步能走到一个目标点[x, y]。题目规定了是一定能走得到的点。我给出如下这个图,显示骑士可以跳的八个空格各自的坐标。

     

    这是在无向图上找最少的步数,所以思路是BFS。你需要意识到无论[x, y]在哪个象限,只要他与(0,0)的距离相等,实际在哪个象限都是等价的。所以一开始我们为了计算方便,就可以把input的这个[x, y]坐标取绝对值。这里我们为了避免走到重复的点,我们需要一个hashset记录遍历过的点。其他部分都是BFS的模板了。有一个细节需要注意的是虽然我们对[x, y]取了绝对值,但是并不意味着路径中不会经过坐标值为负的点。例子就是(0, 0) -> (2, -1) -> (1, 1)。这也就是为什么代码中26行把遍历过的点加入hashset的时候额外判断横纵坐标是否都 >= -1的原因了。

    另外一个优化就是为什么26行我可以限制i和j的范围,那是因为如果你再往外跳,实际你的步数只有可能是更多。例子,比如还是从(0, 0) -> (1, 1),如果你一开始跳到(2,1),你再往比如(4,2)或者(4,0)跳,实际是没有帮助的。

    时间O(mn) 

    空间O(mn)

    Java实现

     1 class Solution {
     2     public int minKnightMoves(int x, int y) {
     3         int[][] dirs = new int[][] { { -1, -2 }, { -1, 2 }, { 1, -2 }, { 1, 2 }, { -2, -1 }, { -2, 1 }, { 2, -1 },
     4                 { 2, 1 } };
     5         x = Math.abs(x);
     6         y = Math.abs(y);
     7         HashSet<String> visited = new HashSet<>();
     8         Queue<int[]> queue = new LinkedList<>();
     9         queue.offer(new int[] { 0, 0 });
    10         visited.add("0,0");
    11 
    12         int step = 0;
    13         while (!queue.isEmpty()) {
    14             int size = queue.size();
    15             while (size-- > 0) {
    16                 int[] cur = queue.poll();
    17                 if (cur[0] == x && cur[1] == y) {
    18                     return step;
    19                 }
    20 
    21                 for (int[] dir : dirs) {
    22                     int i = cur[0] + dir[0];
    23                     int j = cur[1] + dir[1];
    24                     // (0, 0) -> (2, -1) -> (1, 1)
    25                     // +2的意思是多给两个格子的空间以便于骑士跳出去再跳回来的操作
    26                     if (!visited.contains(i + "," + j) && i >= -1 && j >= -1 && i <= x + 2 && j <= y + 2) {
    27                         queue.offer(new int[] { i, j });
    28                         visited.add(i + "," + j);
    29                     }
    30                 }
    31             }
    32             step++;
    33         }
    34         return -1;
    35     }
    36 }

    LeetCode 题目总结

  • 相关阅读:
    FZU 2150 Fire Game
    POJ 3414 Pots
    POJ 3087 Shuffle'm Up
    POJ 3126 Prime Path
    POJ 1426 Find The Multiple
    POJ 3278 Catch That Cow
    字符数组
    HDU 1238 Substing
    欧几里德和扩展欧几里德详解 以及例题CodeForces 7C
    Codeforces 591B Rebranding
  • 原文地址:https://www.cnblogs.com/cnoodle/p/12820573.html
Copyright © 2011-2022 走看看