Solve the task from JS interview about the labyrinth | Maze

Поделиться
HTML-код
  • Опубликовано: 8 сен 2024
  • Одна из частых задач на JS собеседованиях - задача про лабиринт. Есть очень много различных вариаций таких задач. В одних необходимо найти самое короткое решение, в других - первое попавшееся. В этом видео мы разберем задачу, в которой нужно ответить в принципе, имеет ли данный лабиринт решение или нет.
    Даже эта задача имеет множество различных алгоритмов решений, мы рассмотрим вариант с рекурсией.
    Мне попадалась эта задача в очень разных интерпретациях, одна из них была поставлена, как будто бы лабиринт - это полупроводниковая дорожка, по которой может протекать ток, но по этой дорожке разбросаны дефекты, как пиксели. По ним ток не течет. И необходимо понять: при данном расположении дефектов проводит ли эта дорожка сигнал.
    Код с решением: codepen.io/puz...
    ---
    Если видео было для вас полезным, ставьте лайк и поделитесь им с друзьями.
    И обязательно подписывайтесь на наш канал: bit.ly/fs-ytb
    ---
    Присоединяйтесь к нам в соцсетях:
    FB: / frontendscience
    Instagram Сергея Пузанкова: / puzankovcom
    Заходите на наш сайт: frontend-scienc...
    #leetcode, #алгоритмы, #javascript #itсобеседование

Комментарии • 41

  • @frontendscience
    @frontendscience  4 года назад +4

    Друзья, пишите под видео свои решения! Очень полезно и интересно их все читать!

  • @user-rb5gj7ls4n
    @user-rb5gj7ls4n 4 года назад +5

    Обожаю решать ваши задачи. Некоторые из них заставляют сильно попотеть)

    • @frontendscience
      @frontendscience  4 года назад +2

      Обожаем такие комментарии! :)

  • @multiply87
    @multiply87 3 года назад +1

    как обычно, супер. Спасибо за труды)

  • @user-up2rz4se7e
    @user-up2rz4se7e 3 года назад +1

    Спасибо за задачу, минут 30 потратил и вот что получилось без рефакторинга
    function maze(start, end) {
    const lab = [
    [1,1,1,0,0,0],
    [0,0,0,1,0,1],
    [0,1,0,0,0,1],
    [0,1,1,1,1,1],
    [0,0,0,0,0,0]
    ]
    function step(pos) {
    start.x = pos.x
    start.y = pos.y
    lab[pos.y][pos.x] = 2
    const top = { x:pos.x, y:pos.y - 1 }
    const left = { x:pos.x - 1, y:pos.y }
    const right = { x:pos.x + 1, y:pos.y }
    const bottom = { x:pos.x, y:pos.y + 1 }
    if (lab[top.y] !== undefined && !lab[top.y][top.x])
    step(top)
    if (lab[left.y][left.x] !== undefined && !lab[left.y][left.x])
    step(left)
    if (lab[right.y][right.x] !== undefined && !lab[right.y][right.x])
    step(right)
    if (lab[bottom.y] !== undefined && !lab[bottom.y][bottom.x])
    step(bottom)
    }
    step(start)
    return (start.x === end.x && start.y === end.y)
    }
    console.log(maze({ x:3, y:0 }, { x:5, y:4 }))

  • @mikhailreznichenko8035
    @mikhailreznichenko8035 4 года назад +2

    Решения , пока своего нету ) Но видео классное!

  • @gamecenter0
    @gamecenter0 10 месяцев назад +1

    Спасибо большое, но мой мозг сломалась🤯🤯

  • @olegm4602
    @olegm4602 3 года назад

    Спасибо за задачи! У меня вышло такое решение:
    function checkPath(start, end) {
    function step(x, y) {
    // Если вышли за пределы
    if (y < 0) return false;
    if (y >= maze.length) return false;
    if (maze[y][x] === undefined) return false;
    // Если пошли по неверному пути
    if (maze[y][x] === 1) return false;
    if (maze[y][x] === 'x') return false;
    if (x === end.x && y === end.y) return true;
    maze[y][x] = 'x';
    return step(x + 1, y) || step(x - 1, y) || step(x, y + 1) || step(x, y - 1);
    }
    return step(start.x, start.y);
    }

  • @SerzhNesteruk
    @SerzhNesteruk Год назад

    Чуть заморочился над чистотой функции и иммутабельностью внешнего объекта maze. Вот, что получилось:
    const checkPath = (entrance, exit, maze) => {
    const map = Array.from(Array(maze.length), (_, y) => maze[y].map(v => v === 0));
    map.isVisitable = function({x, y}) {
    return this[y]?.hasOwnProperty(x) && this[y][x];
    };
    if (!map.isVisitable(entrance) || !map.isVisitable(exit)) {
    return false;
    }
    (function traversing({x, y}, end, map) {
    map[y][x] = false;
    if (x === end.x && y === end.y) return;
    const directions = [
    {x: x + 1, y: y}, // right
    {x: x, y: y + 1}, // down
    {x: x - 1, y: y}, // left
    {x: x, y: y - 1}, // up
    ];
    for (const variant of directions) {
    if (map.isVisitable(variant)) {
    traversing(variant, end, map);
    }
    }
    }(entrance, exit, map))
    return !map[exit.y][exit.x];
    };

  • @a.osethkin55
    @a.osethkin55 3 года назад

    Рекурсия - это весело, но лучше было бы использовать оценку расстояний (Дейкстры или в ширину вроде называется), тогда стек не надо забивать. #муравьиныйалгоритм

    • @frontendscience
      @frontendscience  3 года назад

      А чем это лучше? Особенно для собеседования? У нас нет условия с ограничением по памяти.

  • @AzamatAbduvohidov99
    @AzamatAbduvohidov99 Год назад

    spasibo

  • @anton-vr5xw
    @anton-vr5xw 3 года назад

    шикарно

  • @alexanderruzhik9234
    @alexanderruzhik9234 2 года назад

    Возможно такой вариант является более простым для понимания или я неправильно понял условие? Но отрабатывает он как надо:
    function checkPath(start, end) {
    let {x, y} = start;
    while (true) {
    if (x === end.x && y === end.y) {
    return true;
    }
    if (maze[y][x] === 0 && maze[y + 1][x] === 0) {
    y++;
    x = 0;
    } else {
    if (x === maze[0].length - 1) {
    return false;
    } else {
    x++;
    }
    }
    }
    }

    • @frontendscience
      @frontendscience  2 года назад

      Такой вариант к сожалению не будет работать на лабиринтах где путь не идет всегда по направлению к выходу. На примере который был в видео - это решение не проходит.

  • @antiga1000
    @antiga1000 2 года назад +1

    function checkPath(start, end){
    const n = maze.length - 1;
    const {x, y} = start;
    const moveTo = (x, y) => {
    if (x < 0 || y < 0 || x > n || y > n || maze[y][x] !== 0) {
    return false;
    }

    maze[y][x] = 5;
    if (x === end.x && y === end.y) {
    return true;
    }

    return moveTo(x - 1, y)
    || moveTo(x + 1, y)
    || moveTo(x, y - 1)
    || moveTo(x, y + 1);
    }

    return moveTo(x, y);
    }

  • @antoncigur2724
    @antoncigur2724 2 года назад

    Самооценка[stonks]=‘dawn’
    Вот скажите, только честно, как долго вы думали над алгоритмом ?

    • @frontendscience
      @frontendscience  2 года назад

      я уже не помню. Давно было. Но вообще сам алгоритм не сложен и очень известен. Эту задачу можно решить либо с помощью DFS либо BFS. Это очень популярные алгоритмы для решения такого рода задач.

    • @TheVakin213
      @TheVakin213 2 года назад

      Я сходу допер только до условий в которых происходит осматривание соседних клеток и формируется массив возможных ходов, до рекурсии не догадался.

  • @sergeykhairulin
    @sergeykhairulin 3 года назад

    Четыре if прям как то больно выглядят. Сделать бы массив ходов и пробегаться циклом по нему. И там же добавлять только 0 значения лабиринта, без фильтра.

    • @frontendscience
      @frontendscience  3 года назад +1

      С одной стороны соглашусь что 4 if выглядят не самым приятным образом - с другой стороны, решение где мы будем проходиться циклом по возможным ходам, будет намного сложней в понимании что же происходит. Если задачу решать именно на собеседовании - настоятельно рекомендую не оптимизировать а оставлять явным образом if'ы.

  • @ovocado9965
    @ovocado9965 4 года назад +2

    1:08 - 5 минут назад ты сказал, что осталось 2 минуты.

  • @yarik83men51
    @yarik83men51 2 года назад

    Пробую на Java, не всегда срабатывает, где то логика у моего скрипта захромала. Если есть идеи как пофиксить, помогите. Спасибо.
    Код:
    import java.util.Arrays;
    public class Maze {
    public static void main(String[] args) {
    // 1 приход
    // 0 не проходной
    // Вход [0, 0], выход [4, 4]
    int[][] maze = {
    {1, 0, 0, 0},
    {1, 1, 0, 0},
    {0, 1, 1, 1},
    {1, 1, 1, 1}
    };
    int[][] maze1 = {
    {1, 0, 0, 0},
    {1, 1, 0, 1},
    {0, 1, 0, 0},
    {0, 1, 0, 1},
    {1, 1, 1, 1}
    };
    int[][] grid = {
    {1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1},
    {1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1},
    {0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0},
    {1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1},
    {1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1},
    {1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1},
    {1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
    System.out.println(checkMaze(maze1, 0, 0, 4, 3));
    Arrays.stream(maze1).forEach(arrayElement -> System.out.println(Arrays.toString(arrayElement)));
    System.out.println(checkMaze(maze, 0, 0, 3, 3));
    Arrays.stream(maze).forEach(arrayElement -> System.out.println(Arrays.toString(arrayElement)));
    System.out.println(checkMaze(grid, 0, 0, 12, 7));
    Arrays.stream(grid).forEach(arrayElement -> System.out.println(Arrays.toString(arrayElement)));
    }
    private static boolean checkMaze(int[][] maze, int col, int row, int endCol, int endRow) {
    maze[col][row] = 5;
    if (col == endCol && row == endRow) {
    return true;
    }
    boolean result = false;
    // up
    if (isValid(col, row - 1, maze) && maze[col][row - 1] != 5
    || (isValid(col, row - 2, maze) && maze[col][row - 1] == 5)
    ) {
    row--;
    result = checkMaze(maze, col, row, endCol, endRow);
    }
    // down
    if (isValid(col, row + 1, maze) && !result && maze[col][row + 1] != 5
    || (isValid(col, row + 2, maze) && maze[col][row + 1] == 5)
    ) {
    row++;
    result = checkMaze(maze, col, row, endCol, endRow);
    }
    // left
    if (isValid(col - 1, row, maze) && !result && maze[col - 1][row] != 5
    || (isValid(col, row, maze) && maze[col - 1][row] == 5)) {
    col--;
    result = checkMaze(maze, col, row, endCol, endRow);
    }
    // right
    if (isValid(col + 1, row, maze) && !result && maze[col + 1][row] != 5
    || (isValid(col, row, maze) && maze[col + 1][row] == 5)) {
    col++;
    result = checkMaze(maze, col, row, endCol, endRow);
    }
    //System.out.println("col = " + col + " " + "row = " + row);
    return result;
    }
    private static boolean isValid(int col, int row, int[][] maze) {
    return col >= 0 && col < maze.length && row >= 0 && row < maze[0].length && maze[col][row] == 1;
    }
    }

  • @alumni7837
    @alumni7837 3 года назад

    В этот раз достаточно трудная задачка для меня, спасибо за ваши труды.
    Вот мое решение. Сейчас буду смотреть ваше.
    function checkPath(start, end) {
    function canIgo(x, y) {
    return x < 6 && x >= 0 && y < 6 && y >= 0 && maze[y][x] === 0
    // определяем есть ли эта позиция и можно ли идти сюда
    }
    function step(x, y) {
    if (x === end.x && y === end.y) return true; // если добрались в конец возвращаем true
    const roads = []; // создаем массив возможных путей
    if (canIgo(x + 1, y)) { //проверяем возможно ли перейти на все возможные позиции
    roads.push([x + 1, y]);
    }
    if (canIgo(x - 1, y)) {
    roads.push([x - 1, y]);
    }
    if (canIgo(x, y + 1)) {
    roads.push([x, y + 1]);
    }
    if (canIgo(x, y - 1)) {
    roads.push([x, y - 1]);
    }
    maze[y][x] = 9; // отмечаем 9-кой текущую позицию как пройденную
    if (roads.length === 0) return false; // если идти больше некуда возвращаем false
    // в зависимости от кол-ва доступных дорог проходим по ним всем
    if (roads.length === 1) return step(roads[0][0], roads[0][1]);
    if (roads.length === 2) return step(roads[0][0], roads[0][1]) ||
    step(roads[1][0], roads[1][1]);
    if (roads.length === 3) return step(roads[0][0], roads[0][1]) ||
    step(roads[1][0], roads[1][1]) ||
    step(roads[2][0], roads[2][1]);
    }
    return step(start.x, start.y);
    }
    console.log(checkPath({x : 3, y: 0},{x: 5, y: 5}));
    console.log(maze);

    • @frontendscience
      @frontendscience  3 года назад

      Благодарю за решение! Круто что вначале сами решили!

  • @denichi872
    @denichi872 10 месяцев назад

    function checkPath(start, end) {
    maze[start.y][start.x] = 5
    const siblings = getValidSib(start);
    if (siblings.length === 0) return false;
    for (let i = 0; i < siblings.length; i++) {
    const {x, y} = siblings[i];
    const isSolved = y === end.y && x === end.x
    if (isSolved || checkPath({x, y}, end)) return true;
    }
    }
    function getValidSib(cord) {
    const {x, y} = cord, cords = [];
    if (maze[y - 1]?.[x] === 0) cords.push({x, y: y - 1});
    if (maze[y + 1]?.[x] === 0) cords.push({x, y: y + 1});
    if (maze[y][x - 1] === 0) cords.push({x: x - 1, y});
    if (maze[y][x + 1] === 0) cords.push({x: x + 1, y});
    return cords;
    }

  • @user-no7sl1yk3f
    @user-no7sl1yk3f 4 месяца назад

    Спасибо
    function checkPath(start, end) {
    const forbiddenCoordinates = {};
    function isForbiddenCoordinates(y, x) {
    return forbiddenCoordinates[y]?.includes(x);
    }
    function isAvailableCoordinates(level, x) {
    return level?.[x] === 0;
    }
    function move(position) {
    const {x, y} = position;
    if (x === end.x && y === end.y) return true;
    const level = maze[y];
    const nextLevel = maze?.[y + 1];
    const availableCoordinates = [];
    if (isAvailableCoordinates(level, x - 1) && !isForbiddenCoordinates(y, x - 1)) availableCoordinates.push({x: x - 1, y});
    if (isAvailableCoordinates(level, x + 1) && !isForbiddenCoordinates(y, x + 1)) availableCoordinates.push({x: x + 1, y});
    if (isAvailableCoordinates(nextLevel, x) && !isForbiddenCoordinates(y + 1, x)) availableCoordinates.push({x: x, y: y + 1});
    forbiddenCoordinates[y] ? forbiddenCoordinates[y].push(x) : forbiddenCoordinates[y] = [x];
    if (availableCoordinates.length === 0) {
    return false;
    }
    for(let coordinate of availableCoordinates) {
    if (move(coordinate)) return true;
    }
    return false;
    }
    return move(start);
    }

  • @user-xt9nl7no8e
    @user-xt9nl7no8e 2 года назад

    function road(arr, position = {x: 5, y: 0}, finish = {x: 5, y: 5}) {
    try {
    let array = [...arr]
    let pos = {...position}
    let fin = {...finish}
    array[pos.y][pos.x] = 5
    //Зачищаємо 9 шоб була видима тільки лінія правильного шляху
    if (pos.x === fin.x && pos.y === pos.x) return array.map(el=>el.map(num=>{
    if (num === 9) return 0
    return num
    }))
    const left = {x: pos.x - 1, y: pos.y}
    const right = {x: pos.x + 1, y: pos.y}
    const up = {x: pos.x, y: pos.y - 1}
    const down = {x: pos.x, y: pos.y + 1}
    const objDirections = {
    left, right, up, down
    }
    const objKeys = Object.keys(objDirections)
    function isEmpty() {
    for (let i = 0; i < objKeys.length; i++) {
    if (array[objDirections[objKeys[i]].x] !== undefined
    && array[objDirections[objKeys[i]].y] !== undefined
    && array[objDirections[objKeys[i]].y][objDirections[objKeys[i]].x] === 0) {
    pos = {...objDirections[objKeys[i]]}
    return true
    }
    }
    array[pos.y][pos.x] = 9
    //Коли впираємось в тупік повертаємось і йдемо назд по 5-кам пока не зустріним 0. Спочатку нас цікавить 0 а потім 5 шоб не піти назад
    for (let i = 0; i < objKeys.length; i++) {
    if (array[objDirections[objKeys[i]].x] !== undefined
    && array[objDirections[objKeys[i]].y] !== undefined
    && array[objDirections[objKeys[i]].y][objDirections[objKeys[i]].x] === 5) {
    pos = {...objDirections[objKeys[i]]}
    return true
    }
    }
    return false
    }
    if (isEmpty()) {
    return road(array, pos, fin)
    }
    return array
    } catch (err) {
    return false
    }
    }

    • @frontendscience
      @frontendscience  2 года назад

      Вау круто вышло! Отлично работает!

  • @edgarhovsepyan3393
    @edgarhovsepyan3393 Год назад +1

    it's my solution .it's not the best but at least works
    let maze = [
    [1, 1, 1, 0, 0, 1],
    [1, 1, 1, 1, 0, 1],
    [0, 0, 0, 0, 0, 0],
    [0, 1, 1, 1, 1, 1],
    [0, 0, 0, 0, 0, 0],
    [1, 1, 1, 1, 1, 0],
    ];
    function checkPath(start,end){
    if(start.x=maze.length){
    return false
    }
    if(start.y=maze.length){
    return false
    }
    if(maze[start.y][start.x]!==0){
    return false
    }
    if(start.x===end.x&&start.y===end.y&&maze[start.x][start.y]===0){
    return true;
    }
    maze[start.y][start.x]=2;
    return checkPath({x:start.x+1,y:start.y}, { x: 5, y: 5 })||checkPath({x:start.x,y:start.y+1}, { x: 5, y: 5 })||
    checkPath({x:start.x-1,y:start.y}, { x: 5, y: 5 })||checkPath({x:start.x,y:start.y-1}, { x: 5, y: 5 })
    }
    debugger;
    console.log(checkPath({ x: 3, y: 0 }, { x: 5, y: 5 }));
    console.log(maze);