1197. Minimum Knight Moves

Il testo del problema è tradotto dal russo per la lingua selezionata. Il codice resta invariato.

На бесконечной шахматной доске с координатами от -бесконечности до +бесконечности у вас есть конь на клетке [0, 0].

У коня есть 8 возможных ходов. Каждый ход представляет собой два квадрата в кардинальном направлении, затем один квадрат в ортогональном направлении.

return минимальное количество шагов, необходимых для перемещения коня на клетку [x, y]. Гарантируется, что ответ существует.

Esempio:

Input: x = 5, y = 5

Output: 4

Explanation: [0, 0] → [2, 1] → [4, 2] → [3, 4] → [5, 5]

C# soluzione

abbinato/originale
public class Solution {
    public int MinKnightMoves(int x, int y) {
        int[][] offsets = new int[][] {
            new int[] {1, 2}, new int[] {2, 1}, new int[] {2, -1}, new int[] {1, -2},
            new int[] {-1, -2}, new int[] {-2, -1}, new int[] {-2, 1}, new int[] {-1, 2}
        };
        
        var originQueue = new Queue<int[]>();
        originQueue.Enqueue(new int[] {0, 0, 0});
        var originDistance = new Dictionary<string, int> {{"0,0", 0}};
        
        var targetQueue = new Queue<int[]>();
        targetQueue.Enqueue(new int[] {x, y, 0});
        var targetDistance = new Dictionary<string, int> {{$"{x},{y}", 0}};
        
        while (true) {
            var origin = originQueue.Dequeue();
            var originKey = $"{origin[0]},{origin[1]}";
            if (targetDistance.ContainsKey(originKey)) {
                return origin[2] + targetDistance[originKey];
            }
            
            var target = targetQueue.Dequeue();
            var targetKey = $"{target[0]},{target[1]}";
            if (originDistance.ContainsKey(targetKey)) {
                return target[2] + originDistance[targetKey];
            }
            
            foreach (var offset in offsets) {
                var nextOrigin = new int[] {origin[0] + offset[0], origin[1] + offset[1], origin[2] + 1};
                var nextOriginKey = $"{nextOrigin[0]},{nextOrigin[1]}";
                if (!originDistance.ContainsKey(nextOriginKey)) {
                    originQueue.Enqueue(nextOrigin);
                    originDistance[nextOriginKey] = nextOrigin[2];
                }
                
                var nextTarget = new int[] {target[0] + offset[0], target[1] + offset[1], target[2] + 1};
                var nextTargetKey = $"{nextTarget[0]},{nextTarget[1]}";
                if (!targetDistance.ContainsKey(nextTargetKey)) {
                    targetQueue.Enqueue(nextTarget);
                    targetDistance[nextTargetKey] = nextTarget[2];
                }
            }
        }
    }
}

C++ soluzione

bozza automatica, rivedere prima dell'invio
#include <bits/stdc++.h>
using namespace std;

// Auto-generated C++ draft from the C# solution. Review containers, LINQ and helper types before submit.
class Solution {
public:
    public int MinKnightMoves(int x, int y) {
        int[][] offsets = new int[][] {
            new int[] {1, 2}, new int[] {2, 1}, new int[] {2, -1}, new int[] {1, -2},
            new int[] {-1, -2}, new int[] {-2, -1}, new int[] {-2, 1}, new int[] {-1, 2}
        };
        
        var originQueue = new queue<int[]>();
        originQueue.Enqueue(new int[] {0, 0, 0});
        var originDistance = new unordered_map<string, int> {{"0,0", 0}};
        
        var targetQueue = new queue<int[]>();
        targetQueue.Enqueue(new int[] {x, y, 0});
        var targetDistance = new unordered_map<string, int> {{$"{x},{y}", 0}};
        
        while (true) {
            var origin = originQueue.Dequeue();
            var originKey = $"{origin[0]},{origin[1]}";
            if (targetDistance.count(originKey)) {
                return origin[2] + targetDistance[originKey];
            }
            
            var target = targetQueue.Dequeue();
            var targetKey = $"{target[0]},{target[1]}";
            if (originDistance.count(targetKey)) {
                return target[2] + originDistance[targetKey];
            }
            
            foreach (var offset in offsets) {
                var nextOrigin = new int[] {origin[0] + offset[0], origin[1] + offset[1], origin[2] + 1};
                var nextOriginKey = $"{nextOrigin[0]},{nextOrigin[1]}";
                if (!originDistance.count(nextOriginKey)) {
                    originQueue.Enqueue(nextOrigin);
                    originDistance[nextOriginKey] = nextOrigin[2];
                }
                
                var nextTarget = new int[] {target[0] + offset[0], target[1] + offset[1], target[2] + 1};
                var nextTargetKey = $"{nextTarget[0]},{nextTarget[1]}";
                if (!targetDistance.count(nextTargetKey)) {
                    targetQueue.Enqueue(nextTarget);
                    targetDistance[nextTargetKey] = nextTarget[2];
                }
            }
        }
    }
}

Java soluzione

abbinato/originale
class Solution {
    public int minKnightMoves(int x, int y) {
        int[][] offsets = {{1, 2}, {2, 1}, {2, -1}, {1, -2},
                {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2}};

        Deque<int[]> originQueue = new LinkedList<>();
        originQueue.addLast(new int[]{0, 0, 0});
        Map<String, Integer> originDistance = new HashMap<>();
        originDistance.put("0,0", 0);

        Deque<int[]> targetQueue = new LinkedList<>();
        targetQueue.addLast(new int[]{x, y, 0});
        Map<String, Integer> targetDistance = new HashMap<>();
        targetDistance.put(x + "," + y, 0);

        while (true) {
            int[] origin = originQueue.removeFirst();
            String originXY = origin[0] + "," + origin[1];
            if (targetDistance.containsKey(originXY)) {
                return origin[2] + targetDistance.get(originXY);
            }

            int[] target = targetQueue.removeFirst();
            String targetXY = target[0] + "," + target[1];
            if (originDistance.containsKey(targetXY)) {
                return target[2] + originDistance.get(targetXY);
            }

            for (int[] offset : offsets) {
                int[] nextOrigin = new int[]{origin[0] + offset[0], origin[1] + offset[1]};
                String nextOriginXY = nextOrigin[0] + "," + nextOrigin[1];
                if (!originDistance.containsKey(nextOriginXY)) {
                    originQueue.addLast(new int[]{nextOrigin[0], nextOrigin[1], origin[2] + 1});
                    originDistance.put(nextOriginXY, origin[2] + 1);
                }

                int[] nextTarget = new int[]{target[0] + offset[0], target[1] + offset[1]};
                String nextTargetXY = nextTarget[0] + "," + nextTarget[1];
                if (!targetDistance.containsKey(nextTargetXY)) {
                    targetQueue.addLast(new int[]{nextTarget[0], nextTarget[1], target[2] + 1});
                    targetDistance.put(nextTargetXY, target[2] + 1);
                }
            }
        }
    }
}

JavaScript soluzione

abbinato/originale
class Solution {
    minKnightMoves(x, y) {
        const offsets = [
            [1, 2], [2, 1], [2, -1], [1, -2],
            [-1, -2], [-2, -1], [-2, 1], [-1, 2]
        ];

        const originQueue = [[0, 0, 0]];
        const originDistance = { '0,0': 0 };

        const targetQueue = [[x, y, 0]];
        const targetDistance = { [`${x},${y}`]: 0 };

        while (true) {
            const [ox, oy, od] = originQueue.shift();
            const originKey = `${ox},${oy}`;
            if (originKey in targetDistance) {
                return od + targetDistance[originKey];
            }

            const [tx, ty, td] = targetQueue.shift();
            const targetKey = `${tx},${ty}`;
            if (targetKey in originDistance) {
                return td + originDistance[targetKey];
            }

            for (const [dx, dy] of offsets) {
                const nextOrigin = [ox + dx, oy + dy, od + 1];
                const nextOriginKey = `${nextOrigin[0]},${nextOrigin[1]}`;
                if (!(nextOriginKey in originDistance)) {
                    originQueue.push(nextOrigin);
                    originDistance[nextOriginKey] = nextOrigin[2];
                }

                const nextTarget = [tx + dx, ty + dy, td + 1];
                const nextTargetKey = `${nextTarget[0]},${nextTarget[1]}`;
                if (!(nextTargetKey in targetDistance)) {
                    targetQueue.push(nextTarget);
                    targetDistance[nextTargetKey] = nextTarget[2];
                }
            }
        }
    }
}

Python soluzione

abbinato/originale
from collections import deque

class Solution:
    def minKnightMoves(self, x: int, y: int) -> int:
        offsets = [(1, 2), (2, 1), (2, -1), (1, -2), (-1, -2), (-2, -1), (-2, 1), (-1, 2)]
        
        origin_queue = deque([(0, 0, 0)])
        origin_distance = {"0,0": 0}
        
        target_queue = deque([(x, y, 0)])
        target_distance = {f"{x},{y}": 0}
        
        while True:
            ox, oy, od = origin_queue.popleft()
            origin_key = f"{ox},{oy}"
            if origin_key in target_distance:
                return od + target_distance[origin_key]
            
            tx, ty, td = target_queue.popleft()
            target_key = f"{tx},{ty}"
            if target_key in origin_distance:
                return td + origin_distance[target_key]
            
            for dx, dy in offsets:
                next_origin = (ox + dx, oy + dy, od + 1)
                next_origin_key = f"{next_origin[0]},{next_origin[1]}"
                if next_origin_key not in origin_distance:
                    origin_queue.append(next_origin)
                    origin_distance[next_origin_key] = next_origin[2]
                
                next_target = (tx + dx, ty + dy, td + 1)
                next_target_key = f"{next_target[0]},{next_target[1]}"
                if next_target_key not in target_distance:
                    target_queue.append(next_target)
                    target_distance[next_target_key] = next_target[2]

Go soluzione

abbinato/originale
package main

import (
    "container/list"
    "fmt"
)

func minKnightMoves(x int, y int) int {
    offsets := [][]int{{1, 2}, {2, 1}, {2, -1}, {1, -2}, {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2}}
    
    originQueue := list.New()
    originQueue.PushBack([]int{0, 0, 0})
    originDistance := map[string]int{"0,0": 0}
    
    targetQueue := list.New()
    targetQueue.PushBack([]int{x, y, 0})
    targetDistance := map[string]int{fmt.Sprintf("%d,%d", x, y): 0}
    
    for {
        origin := originQueue.Remove(originQueue.Front()).([]int)
        originKey := fmt.Sprintf("%d,%d", origin[0], origin[1])
        if targetDistance[originKey] != 0 || originKey == fmt.Sprintf("%d,%d", x, y) {
            return origin[2] + targetDistance[originKey]
        }
        
        target := targetQueue.Remove(targetQueue.Front()).([]int)
        targetKey := fmt.Sprintf("%d,%d", target[0], target[1])
        if originDistance[targetKey] != 0 || targetKey == "0,0" {
            return target[2] + originDistance[targetKey]
        }
        
        for _, offset := range offsets {
            nextOrigin := []int{origin[0] + offset[0], origin[1] + offset[1], origin[2] + 1}
            nextOriginKey := fmt.Sprintf("%d,%d", nextOrigin[0], nextOrigin[1])
            if _, ok := originDistance[nextOriginKey]; !ok {
                originQueue.PushBack(nextOrigin)
                originDistance[nextOriginKey] = nextOrigin[2]
            }
            
            nextTarget := []int{target[0] + offset[0], target[1] + offset[1], target[2] + 1}
            nextTargetKey := fmt.Sprintf("%d,%d", nextTarget[0], nextTarget[1])
            if _, ok := targetDistance[nextTargetKey]; !ok {
                targetQueue.PushBack(nextTarget)
                targetDistance[nextTargetKey] = nextTarget[2]
            }
        }
    }
}

Algorithm

Инициализация структур данных:

Инициализируйте две очереди для хранения координат и расстояний: одну для движения от начальной точки, другую — от конечной точки.

Инициализируйте две карты для хранения посещенных координат и расстояний: одну для движения от начальной точки, другую — от конечной точки.

Implementazione двунаправленного поиска в ширину (BFS):

Выполняйте шаги из очередей, расширяя круги поиска как от начальной, так и от конечной точки.

Если круги пересекаются, возвращайте сумму расстояний до точки пересечения.

Расширение кругов поиска:

Для каждой текущей точки из очередей расширяйте круг поиска по всем возможным ходам коня.

Обновляйте расстояния и добавляйте новые точки в очереди, если они еще не были посещены.

Увеличивайте units на значение, извлеченное из кучи.

😎

Vacancies for this task

offerte attive with overlapping task tags are mostrati.

Tutte le offerte
Non ci sono ancora offerte attive.