es
Feedback
JavaScript | LeetCode

JavaScript | LeetCode

Ir al canal en Telegram

Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @easyoffer_adv

Mostrar más
8 365
Suscriptores
-424 horas
-297 días
-11230 días
Archivo de publicaciones
Задача: 1020. Number of Enclaves Сложность: medium Вам дана двоичная матричная сетка m x n, где 0 обозначает морскую ячейку, а 1 - сухопутную. Ход состоит из перехода от одной сухопутной ячейки к другой соседней (в 4-х направлениях) или выхода за границу сетки. Верните количество сухопутных ячеек в сетке, для которых мы не можем выйти за границу сетки за любое количество ходов. Пример:
Input: grid = [[0,0,0,0],[1,0,1,0],[0,1,1,0],[0,0,0,0]]
Output: 3
👨‍💻 Алгоритм: 1⃣Обработка граничных сухопутных ячеек: Пройдитесь по всем ячейкам, которые находятся на границе сетки (первый и последний ряды, первый и последний столбцы). Если ячейка содержит 1, начните поиск в глубину (DFS) или поиск в ширину (BFS), чтобы пометить все достижимые из нее сухопутные ячейки как посещенные. 2⃣Проверка всех ячеек: Пройдите по всем ячейкам матрицы, считая количество сухопутных ячеек, которые не были посещены в предыдущем шаге. 3⃣Возврат результата: Верните количество не посещенных сухопутных ячеек. 😎 Решение:
class Solution {
    numEnclaves(grid) {
        const m = grid.length, n = grid[0].length;
        
        const dfs = (x, y) => {
            if (x < 0 || y < 0 || x >= m || y >= n || grid[x][y] !== 1) {
                return;
            }
            grid[x][y] = 0;
            dfs(x + 1, y);
            dfs(x - 1, y);
            dfs(x, y + 1);
            dfs(x, y - 1);
        };
        
        for (let i = 0; i < m; i++) {
            if (grid[i][0] === 1) dfs(i, 0);
            if (grid[i][n - 1] === 1) dfs(i, n - 1);
        }
        
        for (let j = 0; j < n; j++) {
            if (grid[0][j] === 1) dfs(0, j);
            if (grid[m - 1][j] === 1) dfs(m - 1, j);
        }
        
        let count = 0;
        for (let i = 0; i < m; i++) {
            for (let j = 0; j < n; j++) {
                if (grid[i][j] === 1) {
                    count++;
                }
            }
        }
        
        return count;
    }
}
Ставь 👍 и забирай 📚 Базу знаний

Аренда VPS/VDS-сервера. Виртуальные выделенные серверы в дата-центрах уровня Tier III — 7 готовых конфигураций от 200 ₽/мес.
Аренда VPS/VDS-сервера. Виртуальные выделенные серверы в дата-центрах уровня Tier III — 7 готовых конфигураций от 200 ₽/мес. Преимущества аренды: - Выделенные ресурсы без переплаты; - KVM-виртуализация; - Быстрые NVMe SSD; - Бесплатная защита от DDoS; - Управление через панель, API и Terraform; - Техподдержка 24/7. Запустите сервер за несколько минут! Попробовать #реклама 16+ selectel.ru О рекламодателе

Задача: 477. Total Hamming Distance Сложность: medium Хэммингово расстояние между двумя целыми числами — это количество позиций, в которых соответствующие биты отличаются. Дан целочисленный массив nums, верните сумму Хэмминговых расстояний между всеми парами чисел в nums. Пример:
Input: nums = [4,14,2]
Output: 6
Explanation: In binary representation, the 4 is 0100, 14 is 1110, and 2 is 0010 (just
showing the four bits relevant in this case).
The answer will be:
HammingDistance(4, 14) + HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6.
👨‍💻 Алгоритм: 1⃣Для каждой уникальной пары элементов из массива вычисляем битовое XOR, чтобы найти позиции, где биты различаются. Бит, равный 1 в результате, указывает на различие. 2⃣Для каждой пары элементов используем XOR, чтобы получить битовую разницу, и подсчитываем количество битов, равных 1, чтобы определить Хэммингово расстояние между парой. 3⃣Суммируем все Хэмминговы расстояния для всех пар, чтобы получить общую сумму Хэмминговых расстояний. 😎 Решение:
function totalHammingDistance(nums) {
    let ans = 0;

    if (nums.length === 0) {
        return ans;
    }

    for (let i = 0; i < nums.length - 1; i++) {
        for (let j = i + 1; j < nums.length; j++) {
            ans += (nums[i] ^ nums[j]).toString(2).split('1').length - 1;
        }
    }

    return ans;
}
Ставь 👍 и забирай 📚 Базу знаний

Услуги дата-центра в Москве Размещение и аренда серверного оборудования в дата-центре. 👍 4 современных дата-центра в Москве.
Услуги дата-центра в Москве Размещение и аренда серверного оборудования в дата-центре. 👍 4 современных дата-центра в Москве. 👍 Лицензированный оператор связи. 👍 Индивидуальные конфигурации выделенных серверов под задачи клиента. 👍 Круглосуточная техническая поддержка в Телеграм, без ботов. Узнать цену #реклама 16+ itsoft.ru О рекламодателе

Задача: 514. Freedom Trail Сложность: hard В видеоигре Fallout 4 в квесте "Дорога к свободе" игрокам нужно добраться до металлического диска, называемого "Кольцо Свободы", и использовать его для набора определённого ключевого слова, чтобы открыть дверь. Дана строка ring, представляющая код, выгравированный на внешнем кольце, и другая строка key, представляющая ключевое слово, которое нужно набрать. Верните минимальное количество шагов, чтобы набрать все символы ключевого слова. Изначально первый символ кольца выровнен в направлении "12 часов". Вы должны набирать все символы из строки key один за другим, поворачивая кольцо по часовой или против часовой стрелки, чтобы каждый символ строки key выровнять в направлении "12 часов", а затем нажимая на центральную кнопку. На этапе вращения кольца для набора символа key[i]: Вы можете вращать кольцо по часовой или против часовой стрелки на одно место, что считается одним шагом. Конечная цель вращения — выровнять один из символов кольца в направлении "12 часов", и этот символ должен быть равен key[i]. Если символ key[i] уже выровнен в направлении "12 часов", нажмите центральную кнопку, чтобы набрать его, что также считается одним шагом. После нажатия вы можете начинать набирать следующий символ из key (следующий этап). Иначе, вы завершили весь набор. Пример:
Input: ring = "godding", key = "godding"
Output: 13
👨‍💻 Алгоритм: 1⃣Определите функцию countSteps для вычисления минимального пути между двумя индексами кольца ring. Создайте переменные ringLen и keyLen для хранения длин кольца и ключа соответственно. Создайте словарь bestSteps для хранения минимального количества шагов для нахождения символа на keyIndex, когда ringIndex кольца выровнен в позиции "12 часов". 2⃣Определите функцию tryLock, которая возвращает минимальное количество шагов для набора ключевого слова. Параметры: ringIndex, keyIndex, minSteps (минимальные шаги для набора ключевого слова на данный момент). Проверьте, равен ли keyIndex значению keyLen; если да, верните 0. Проверьте, есть ли пара (ringIndex, keyIndex) в bestSteps. Если есть, верните bestSteps[ringIndex][keyIndex]. Пройдите по каждому charIndex в ring. Если ring[charIndex] равен key[keyIndex], вычислите totalSteps, добавляя результат countSteps, единицу (нажатие центральной кнопки) и результат tryLock для следующего символа в key. Сохраните минимальное значение между totalSteps и текущим minSteps в minSteps. Сохраните minSteps для (ringIndex, keyIndex) в bestSteps. 3⃣Вызовите tryLock(0, 0, INT_MAX), начиная с нулевого индекса ring в позиции "12 часов" и первого символа в key. Наибольшее целое число передается как последний параметр, так как путь между нулевым индексом ring и первым символом key еще не определен. 😎 Решение:
class Solution {
    findRotateSteps(ring, key) {
        const ringLen = ring.length;
        const keyLen = key.length;
        const bestSteps = new Map();
        
        const countSteps = (curr, next) => {
            const stepsBetween = Math.abs(curr - next);
            const stepsAround = ringLen - stepsBetween;
            return Math.min(stepsBetween, stepsAround);
        }
        
        const tryLock = (ringIndex, keyIndex) => {
            const keyPair = `${ringIndex}-${keyIndex}`;
            if (bestSteps.has(keyPair)) {
                return bestSteps.get(keyPair);
            }
            
            if (keyIndex === keyLen) {
                bestSteps.set(keyPair, 0);
                return 0;
            }
            
            let minSteps = Infinity;
            for (let charIndex = 0; charIndex < ringLen; charIndex++) {
                if (ring[charIndex] === key[keyIndex]) {
                    minSteps = Math.min(minSteps, 
                        countSteps(ringIndex, charIndex) + 1 + tryLock(charIndex, keyIndex + 1));
                }
            }
            bestSteps.set(keyPair, minSteps);
            return minSteps;
        }
        
        return tryLock(0, 0);
    }
}
Ставь 👍 и забирай 📚 Базу знаний

🔴AI кодинг интервью с разработчиком из международного FinTech в четверг в 19:00 ДА! Вайбкодинг реально начали проверять на и
🔴AI кодинг интервью с разработчиком из международного FinTech в четверг в 19:00 ДА! Вайбкодинг реально начали проверять на интервью, поэтому мы нашли собеседующего, который проводит AI-секцию в международном финтехе, чтобы вы увидели что на ней спрашивают и как к ней подготовиться. Как это будет: 📂 Александр Дмитриев, разработчик из известного международного финтеха, ex-VK, ex-Ozon проведет вайбкодинг секцию разработчику-добровольцу; 📂 Александр будет задавать реальные вопросы с секций, которые проводил сам и комментировать ответы; 📂 В конце можно будет задать любой вопрос Александру. Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для разработчиков, которые хотят сменить работу, повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_front_bot Реклама. О рекламодателе.

Бесплатный курс по дизайну в FIGMA от Yudaev School Онлайн-программа с наставником и чатом. Внимание! 80% практики. ✅По результату обучения у вас будет портфолио из нескольких работ. ✅Сертификат о прохождении курса. ✅Возможность пройти полное обучение и получить карьерное сопровождение! Учитесь дизайну у профессионалов в Yudaev Shool. Переходи по кнопки: "Подробнее" и начинай свое обучение. Доступ 0 руб. Узнать больше #реклама 16+ yudaevschool24.online О рекламодателе

Задача: 169. Majority Element Сложность: easy Дан массив nums размера n, верните элемент большинства. Элемент большинства — это элемент, который встречается более чем ⌊n / 2⌋ раз. Можно предположить, что элемент большинства всегда существует в массиве. Пример:
Input: nums = [3,2,3]
Output: 3
👨‍💻 Алгоритм: 1️⃣Использование HashMap для подсчета: Создайте HashMap для отслеживания количества каждого элемента в массиве. 2️⃣Подсчет вхождений элементов: Пройдите по массиву nums, увеличивая счетчик в HashMap для каждого элемента. 3️⃣Поиск элемента большинства: Определите элемент большинства, просмотрев HashMap и найдя ключ с максимальным значением, которое должно быть больше ⌊n / 2⌋ 😎 Решение:
var majorityElement = function (nums) {
    let counts = {};
    for (let num of nums) {
        if (!counts[num]) {
            counts[num] = 1;
        } else {
            counts[num]++;
        }
    }

    for (let num in counts) {
        if (counts[num] > nums.length / 2) return Number(num);
    }
    return 0;
};
Ставь 👍 и забирай 📚 Базу знаний

Скидки до 50% на посудомоечные машины Kuppersberg Посудомоечные машины Kuppersberg со скидками на Яндекс Маркете! Узнать боль
Скидки до 50% на посудомоечные машины Kuppersberg Посудомоечные машины Kuppersberg со скидками на Яндекс Маркете! Узнать больше #реклама market.yandex.ru О рекламодателе

Задача: 395. Longest Substring with At Least K Repeating Characters Сложность: medium Дана строка s и целое число k, верните длину самой длинной подстроки строки s, такая что частота каждого символа в этой подстроке больше или равна k. Если такой подстроки не существует, верните 0. Пример:
Input: s = "aaabb", k = 3
Output: 3
Explanation: The longest substring is "aaa", as 'a' is repeated 3 times.
👨‍💻 Алгоритм: 1⃣Генерируйте подстроки из строки s, начиная с индекса start и заканчивая индексом end. Используйте массив countMap для хранения частоты каждого символа в подстроке. 2⃣Метод isValid использует countMap для проверки, что каждый символ в подстроке встречается как минимум k раз. Если условие выполняется, текущая подстрока считается допустимой. 3⃣Отслеживайте максимальную длину допустимой подстроки, обновляя её, когда найдена более длинная подстрока, удовлетворяющая условиям. В конце возвращайте длину самой длинной подстроки. 😎 Решение:
function longestSubstring(s, k) {
    if (s.length === 0 || k > s.length) {
        return 0;
    }
    let result = 0;

    for (let start = 0; start < s.length; start++) {
        let countMap = new Array(26).fill(0);
        for (let end = start; end < s.length; end++) {
            countMap[s.charCodeAt(end) - 97]++;
            if (isValid(countMap, k)) {
                result = Math.max(result, end - start + 1);
            }
        }
    }
    return result;
}

function isValid(countMap, k) {
    let countLetters = 0, countAtLeastK = 0;
    for (let count of countMap) {
        if (count > 0) countLetters++;
        if (count >= k) countAtLeastK++;
    }
    return countLetters === countAtLeastK;
}

console.log(longestSubstring("aaabb", 3)); // Output: 3
console.log(longestSubstring("ababbc", 2)); // Output: 5
Ставь 👍 и забирай 📚 Базу знаний

Что будет работать в рекламе завтра? Ответ ищем вместе на REKONFA 2026. 15 октября соберёмся в Москве и онлайн, чтобы обсудит
Что будет работать в рекламе завтра? Ответ ищем вместе на REKONFA 2026. 15 октября соберёмся в Москве и онлайн, чтобы обсудить новые технологии Яндекс Рекламы, продуктовые запуски, тренды рынка, исследования и реальные кейсы. В программе — выступления экспертов и возможность поговорить с продуктовыми командами Яндекс Рекламы о своих задачах. А вне сцены вас ждут коворкинг, фотозоны и форматы для новых знакомств. Участвовать можно в Москве на ВТБ Арене или онлайн. Регистрация бесплатная. Зарегистрироваться #реклама 18+ ya.rekonfa.ru О рекламодателе

Задача: 765. Couples Holding Hands Сложность: hard Есть n пар, сидящих на 2n местах, расположенных в ряд, и они хотят держаться за руки. Люди и места представлены массивом целых чисел row, где row[i] — это ID человека, сидящего на i-м месте. Пары пронумерованы по порядку: первая пара — (0, 1), вторая пара — (2, 3) и так далее, до последней пары — (2n - 2, 2n - 1). Верните минимальное количество перестановок, чтобы каждая пара сидела рядом. Перестановка состоит из выбора любых двух человек, которые встают и меняются местами. Пример:
Input: row = [0,2,1,3]
Output: 1
Explanation: We only need to swap the second (row[1]) and third (row[2]) person.
👨‍💻 Алгоритм: 1⃣Мы могли бы предположить без доказательства, что решение, при котором мы делаем людей на каждом диване счастливыми по порядку, является оптимальным. Это предположение сильнее, чем гипотеза о жадном подходе, но кажется разумным, поскольку при каждом ходе мы делаем хотя бы одну пару счастливой. 2⃣При таком предположении, для какого-то дивана с несчастливыми людьми X и Y, мы либо заменяем Y на партнера X, либо заменяем X на партнера Y. Для каждой из двух возможностей мы можем попробовать оба варианта, используя подход с возвратом. 3⃣Для каждого дивана с двумя возможностями (т.е. оба человека на диване несчастливы) мы попробуем первый вариант, найдем ответ как ans1, затем отменим наш ход и попробуем второй вариант, найдем связанный ответ как ans2, отменим наш ход и затем вернем наименьший ответ. 😎 Решение:
class Solution {
    minSwapsCouples(row) {
        this.N = row.length / 2;
        this.pairs = Array.from({ length: this.N }, (_, i) => [Math.floor(row[2 * i] / 2), Math.floor(row[2 * i + 1] / 2)]);
        return this.solve(0);
    }

    swap(a, b, c, d) {
        const t = this.pairs[a][b];
        this.pairs[a][b] = this.pairs[c][d];
        this.pairs[c][d] = t;
    }

    solve(i) {
        if (i === this.N) return 0;
        const x = this.pairs[i][0], y = this.pairs[i][1];
        if (x === y) return this.solve(i + 1);

        let jx = 0, kx = 0, jy = 0, ky = 0;
        for (let j = i + 1; j < this.N; ++j) {
            for (let k = 0; k <= 1; ++k) {
                if (this.pairs[j][k] === x) { jx = j; kx = k; }
                if (this.pairs[j][k] === y) { jy = j; ky = k; }
            }
        }

        this.swap(i, 1, jx, kx);
        const ans1 = 1 + this.solve(i + 1);
        this.swap(i, 1, jx, kx);

        this.swap(i, 0, jy, ky);
        const ans2 = 1 + this.solve(i + 1);
        this.swap(i, 0, jy, ky);

        return Math.min(ans1, ans2);
    }
}
Ставь 👍 и забирай 📚 Базу знаний

Получите удаленную подработку, где платят 5.000 ₽ в день Нужно заполнять карточки товаров на ВБ, писать описания товаров и от
Получите удаленную подработку, где платят 5.000 ₽ в день Нужно заполнять карточки товаров на ВБ, писать описания товаров и отвечать на отзывы. Все это вы делаете из дома. Бесплатная регистрация только сегодня! Опыт, знания и город — не важны! От вас требуется только телефон. Занятость 3-6 часов в день. График свободный. Заработок зависит от вас. Над вами нет никаких начальников. А самое важное, у вас не будет нужды просыпаться в 6 утра на работу. Для старта в профессии нужно пройти бесплатное 3х-дневное обучение: ✅ Прямые эфиры, где вы поймете суть профессии ✅ Домашки с проверкой и оплатой бонусами ✅ Платим 10 тыс за каждую выполненную домашку Все кто пройдет курс, получат сертификат от школы с образовательной лицензией. ⚡ Начинаем в понедельник! Жмите снизу "Зарегистрироваться": Зарегистрироваться #реклама 16+ course.wildcard.ru О рекламодателе

Задача: 326. Power of Three Сложность: easy Дано целое число n. Верните true, если оно является степенью тройки, иначе верните false. Целое число n является степенью тройки, если существует целое число x такое, что n == 3^x. Пример:
Input: n = 27
Output: true
Explanation: 27 = 3^3
👨‍💻 Алгоритм: 1⃣Проверка начального значения Если n меньше или равно нулю, вернуть false, так как степени тройки всегда положительны. 2⃣Цикл деления на 3 Пока n делится на 3 без остатка, делите n на 3. Повторяйте этот процесс до тех пор, пока n делится на 3. 3⃣Проверка конечного значения Если после всех делений значение n стало равно 1, значит исходное число является степенью тройки, вернуть true. В противном случае вернуть false. 😎 Решение:
var isPowerOfThree = function(n) {
    if (n <= 0) return false;
    while (n % 3 === 0) {
        n = Math.floor(n / 3);
    }
    return n === 1;
};
Ставь 👍 и забирай 📚 Базу знаний

YaC/e 2026: актуальные знания для работы с учениками Онлайн-конференция от Яндекса для учителей, преподавателей и репетиторов
YaC/e 2026: актуальные знания для работы с учениками Онлайн-конференция от Яндекса для учителей, преподавателей и репетиторов, которые хотят быть в курсе технологий в обучении. 30 сентября, онлайн, бесплатно. Каждый получит сертификат участника. Регистрируйтесь до 29 сентября! Узнать больше #реклама 16+ yace.yandex.ru О рекламодателе

Задача: 1512. Number of Good Pairs Сложность: easy Дан массив целых чисел nums, верните количество хороших пар. Пара (i, j) называется хорошей, если nums[i] == nums[j] и i < j. Пример:
Input: nums = [1,2,3,1,1,3]
Output: 4
Explanation: There are 4 good pairs (0,3), (0,4), (3,4), (2,5) 0-indexed.
👨‍💻 Алгоритм: 1⃣Инициализируйте переменную ans значением 0. 2⃣Итерируйте i от 0 до nums.length: Итерируйте j от i + 1 до nums.length: Если nums[i] == nums[j], увеличьте ans на 1. 3⃣Верните ans. 😎 Решение:
var numIdenticalPairs = function(nums) {
    let ans = 0
    for (let i = 0; i < nums.length; i++) {
        for (let j = i + 1; j < nums.length; j++) {
            if (nums[i] === nums[j]) {
                ans++
            }
        }
    }
    return ans
}\
Ставь 👍 и забирай 📚 Базу знаний

Rust + Tauri: лёгкая альтернатива Electron для десктопа ⚡ Electron позволяет быстро делать кроссплатформенные приложения, но
Rust + Tauri: лёгкая альтернатива Electron для десктопа ⚡ Electron позволяет быстро делать кроссплатформенные приложения, но вместе с ним вы получаете большой runtime. Rust + Tauri позволяют использовать HTML/CSS/JS для интерфейса, а Rust — для производительной и безопасной серверной логики. 📅 23 сентября в 20:00 на открытом вебинаре разберём полный цикл разработки GUI на Rust с Tauri 2: структуру проекта, связь Rust и UI, работу с данными, permissions и capabilities, асинхронность, отладку и сборку. 💻 Вебинар для фронтенд-разработчиков, Rust-разработчиков и тех, кто хочет уйти от Electron. ✅ В результате сможете создавать кроссплатформенные приложения и безопасно связывать UI с логикой на Rust. Записаться #реклама 16+ otus.ru О рекламодателе

Задача: 295. Find Median from Data Stream Сложность: hard Медиана — это среднее значение в упорядоченном списке целых чисел. Если размер списка четный, то медианы нет, и медиана — это среднее арифметическое двух средних значений. Например, для arr = [2, 3, 4] медиана равна 3. Например, для arr = [2, 3] медиана равна (2 + 3) / 2 = 2.5. Реализуйте класс MedianFinder: MedianFinder() инициализирует объект MedianFinder. void addNum(int num) добавляет целое число num из потока данных в структуру данных. double findMedian() возвращает медиану всех элементов на данный момент. Ответы с точностью до 10^-5 от фактического ответа будут приниматься. Пример:
Input
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
Output
[null, null, null, 1.5, null, 2.0]

Explanation
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1);    // arr = [1]
medianFinder.addNum(2);    // arr = [1, 2]
medianFinder.findMedian(); // return 1.5 (i.e., (1 + 2) / 2)
medianFinder.addNum(3);    // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0
👨‍💻 Алгоритм: 1⃣Храните числа в контейнере с возможностью изменения размера: Создайте массив для хранения чисел. 2⃣Добавление нового числа: Добавьте новое число в массив. 3⃣Вычисление и вывод медианы: Отсортируйте массив. Если размер массива нечетный, верните среднее значение массива. Если размер массива четный, верните среднее арифметическое двух средних значений массива. 😎 Решение:
class MedianFinder {
    constructor() {
        this.numbers = [];
    }

    addNum(num) {
        this.numbers.push(num);
    }

    findMedian() {
        this.numbers.sort((a, b) => a - b);
        const n = this.numbers.length;
        if (n % 2 === 0) {
            return (this.numbers[Math.floor(n / 2) - 1] + this.numbers[Math.floor(n / 2)]) / 2.0;
        } else {
            return this.numbers[Math.floor(n / 2)];
        }
    }
}
Ставь 👍 и забирай 📚 Базу знаний

Яндекс Музыка до 360 дней бесплатно Яндекс Музыка для вас и 3-х ваших близких. Кинопоиск и Яндекс Книги тоже в мультиподписке
Яндекс Музыка до 360 дней бесплатно Яндекс Музыка для вас и 3-х ваших близких. Кинопоиск и Яндекс Книги тоже в мультиподписке Плюс. Попробуйте бесплатно❤️ Слушать #реклама 18+ music.yandex.ru О рекламодателе

Задача: 210. Course Schedule II Сложность: medium Всего есть numCourses курсов, которые вы должны пройти, пронумерованных от 0 до numCourses - 1. Вам дан массив prerequisites, где prerequisites[i] = [ai, bi] указывает на то, что вы должны сначала пройти курс bi, если хотите взять курс ai. Например, пара [0, 1] указывает на то, что для прохождения курса 0 сначала нужно пройти курс 1. Верните порядок курсов, которые вы должны пройти, чтобы завершить все курсы. Если существует несколько правильных ответов, верните любой из них. Если невозможно завершить все курсы, верните пустой массив. Пример:
Input: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
Output: [0,2,1,3]
Объяснение: Всего есть 4 курса, которые нужно пройти. Чтобы взять курс 3, вы должны завершить оба курса 1 и 2. Оба курса 1 и 2 должны быть взяты после того, как вы завершите курс 0.
Таким образом, один из правильных порядков курсов — [0,1,2,3]. Другой правильный порядок — [0,2,1,3].
👨‍💻 Алгоритм: 1️⃣ Инициализация и построение графа: Инициализируйте стек S, который будет содержать топологически отсортированный порядок курсов в нашем графе. Постройте список смежности, используя пары ребер, указанные на входе. Важно отметить, что пара вида [a, b] указывает на то, что курс b должен быть пройден, чтобы взять курс a. Это подразумевает ребро вида b ➔ a. Учтите это при реализации алгоритма. 2️⃣ Запуск поиска в глубину (DFS): Для каждого узла в нашем графе выполните поиск в глубину (DFS), если этот узел еще не был посещен во время DFS другого узла. Предположим, что мы выполняем поиск в глубину для узла N. Рекурсивно обойдите всех соседей узла N, которые еще не были обработаны. 3️⃣ Обработка узлов и возвращение результата: После обработки всех соседей добавьте узел N в стек. Мы используем стек для моделирования необходимого порядка. Когда мы добавляем узел N в стек, все узлы, которые требуют узел N в качестве предшественника (среди других), уже будут в стеке. После обработки всех узлов просто верните узлы в порядке их присутствия в стеке от вершины до основания. 😎 Решение:
class Solution {
    constructor() {
        this.WHITE = 1;
        this.GRAY = 2;
        this.BLACK = 3;
        this.isPossible = true;
        this.color = new Map();
        this.adjList = new Map();
        this.topologicalOrder = [];
    }

    findOrder(numCourses, prerequisites) {
        for (let i = 0; i < numCourses; i++) {
            this.color.set(i, this.WHITE);
        }

        for (let [dest, src] of prerequisites) {
            if (!this.adjList.has(src)) {
                this.adjList.set(src, []);
            }
            this.adjList.get(src).push(dest);
        }

        for (let i = 0; i < numCourses && this.isPossible; i++) {
            if (this.color.get(i) === this.WHITE) {
                this.dfs(i);
            }
        }

        if (this.isPossible) {
            const order = new Array(numCourses);
            for (let i = 0; i < numCourses; i++) {
                order[i] = this.topologicalOrder[numCourses - i - 1];
            }
            return order;
        } else {
            return [];
        }
    }

    dfs(node) {
        if (!this.isPossible) return;
        this.color.set(node, this.GRAY);

        if (this.adjList.has(node)) {
            for (let neighbor of this.adjList.get(node)) {
                if (this.color.get(neighbor) === this.WHITE) {
                    this.dfs(neighbor);
                } else if (this.color.get(neighbor) === this.GRAY) {
                    this.isPossible = false;
                }
            }
        }

        this.color.set(node, this.BLACK);
        this.topologicalOrder.push(node);
    }
}
Ставь 👍 и забирай 📚 Базу знаний