главная новое лучшее написать
3

Ссылка на задачу — 2115. Find All Possible Recipes from Given Supplies.
В этой задаче для эффективного решения важно не только выбрать эффективный алгоритм, но и аккуратно разложить строки по необходимым структурам данных, избежать лишних копирований и обеспечить ясную картину ownership'a за объектами.

📌 Описание задачи

💡 Идея

Используем рекурсивный DFS для проверки доступности рецептов.
Чтобы избежать повторных вычислений, применяем мемоизацию (кеширование уже проверенных результатов).

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

🔍 Детали подхода

  1. Предобработка входных данных:
    • Создаём хеш-таблицу для быстрого доступа к индексу каждого рецепта.
    • Добавляем начальные запасы в кеш доступных ингредиентов.

Читать дальше →

ответить
3

Ссылка на задачу — 3108. Minimum Cost Walk in Weighted Graph.

📌 Описание задачи

Пример

💡 Идея

Читать дальше →

1 ответ
3

Ссылка на задачу — 2401. Longest Nice Subarray.

📌 Описание задачи

Дан массив nums, состоящий из целых чисел.
Нужно найти наибольший подмассив, в котором ни одна пара чисел не имеет общих установленных битов
(т.е. их побитовое И (&) равно 0).

Пример

💡 Идея

Будем решать задачу в чистом функциональном стиле, используя технику скользящего окна.

Читать дальше →

1 ответ
3

Ссылка на задачу — 3480. Maximize Subarrays After Removing One Conflicting Pair.

📌 Описание задачи

Пример

💡 Идея

Читать дальше →

ответить
3

Ссылка на задачу — 2226. Maximum Candies Allocated to K Children.

📌 Описание задачи

Дан массив candies, где candies[i] — это количество конфет в i-й куче. Нужно раздать конфеты k детям так, чтобы каждый ребёнок получил одинаковое количество конфет и все конфеты одного ребёнка были взяты из одной кучи.
Требуется найти максимальное возможное количество конфет, которое может получить каждый ребёнок.

💡 Идея

Перебор всех возможных вариантов распределения неэффективен. Вместо этого воспользуемся бинарным поиском по ответу:

Будем проверять, можно ли выдать каждому ребёнку candies_per_child конфет.
Если да, увеличиваем candies_per_child, иначе уменьшаем.

🛠 Подробности метода

  1. Вычисляем total_candies — суммарное количество конфет.
  2. Условие быстрого выхода: если total_candies < k, сразу возвращаем 0.
  3. Определяем предикат can_share, который проверяет, можно ли распределить candies_per_child конфет на k детей.

Читать дальше →

ответить
3

Ссылка на задачу — 3356. Zero Array Transformation II.

📝 Описание задачи

Дан массив nums длины N и список запросов queries, каждый из которых задаётся как [li, ri, vali]. Запрос означает, что значения в диапазоне [li, ri] можно уменьшить на любое число от 0 до vali независимо друг от друга.

Нужно найти минимальное число первых запросов k, после которых nums может превратится в массив, состоящий только из нулей. Если это невозможно — вернуть -1.

💡 Идея

Вместо того, чтобы изменять nums напрямую, будем хранить массив последовательных изменений к декременту (updates). Он позволяет эффективно применять диапазонные операции без лишних вычислений.

Чтобы минимизировать количество обработанных запросов, будем использовать жадную стратегию обработки запросов:

⚙️ Детали подхода

  1. Используем массив updates (N+1 элементов), где updates[i] хранит последовательные изменения к декременту значений.

Читать дальше →

ответить
3

Ссылка на задачу — 3479. Fruits Into Baskets III.

📌 Описание задачи

У нас есть два массива:

Нужно распределить фрукты по корзинам слева направо по следующим правилам:

Требуется вернуть количество неразмещённых фруктов.

💡 Идея

Используем дерево отрезков для эффективного поиска первой подходящей корзины.
Это позволит быстро находить и обновлять вместимость корзин за логарифмическое время, что намного быстрее наивного перебора.

🔍 Подробности подхода

  1. Построение дерева отрезков 🌳:
    • Создаём дерево отрезков для максимумов на интервалах, инициализируюя его вместимостями корзин.

Читать дальше →

ответить
3

Ссылка на задачу — 3306. Count of Substrings Containing Every Vowel and K Consonants II.

📌 Условие задачи

Дана строка word и неотрицательное число k.
Необходимо подсчитать количество подстрок, в которых встречаются все гласные буквы ('a', 'e', 'i', 'o', 'u') хотя бы по одному разу и ровно k согласных.

💡 Идея

Будем использовать подход «скользящего окна», отслеживая позиции последних появлений гласных и согласных букв.
Это позволяет эффективно перемещать границы окна и быстро проверять условия задачи при изменении количества согласных и наличии всех гласных.

🛠️ Детали подхода

  1. Для каждой гласной буквы сохраняется её последняя позиция.
  2. Для согласных используется итератор, последовательно предоставляющий позиции согласных в строке.
  3. Если количество согласных становится больше k, левая граница окна перемещается вперёд.
  4. При каждом совпадении условий (ровно k согласных и присутствуют все гласные) подсчитывается количество допустимых подстрок.

⏳ Асимптотика

Читать дальше →

ответить
3

Ссылка на задачу — 2379. Minimum Recolors to Get K Consecutive Black Blocks.

📌 Описание задачи

Дана строка blocks, состоящая из символов 'W' (белый) и 'B' (чёрный).
Необходимо определить минимальное число перекрашиваний белых блоков в чёрные, чтобы получить хотя бы одну последовательность из k подряд идущих чёрных блоков.

💡 Идея

Используем технику скользящего окна:

📖 Детали подхода

  1. Посчитаем число белых блоков в первом окне размера k.
  2. Сдвигаем окно вправо на один символ за раз:
    • если символ, который «входит» в окно, белый ('W'), увеличиваем счётчик;
    • если символ, который «выходит» из окна, белый, уменьшаем счётчик.
  3. После каждого сдвига окна обновляем минимальное найденное значение.
  4. Итоговый ответ — это минимальное число белых блоков за всё время обхода.

⏳ Асимптотика

🛠️ Исходный код

impl Solution {
    pub fn minimum_recolors(blocks: String, k: i32) -> i32 {
        let blocks = blocks.as_bytes();
        let k = k as usize;

        // Count white blocks ('W') in the first window of size k
        let initial_recolors = blocks[..k].iter().filter(|&&b| b == b'W').count() as i32;

        // Slide window over the blocks using iterator methods
        blocks
            .windows(k+1)
            .fold((initial_recolors, initial_recolors), |(current, min), window| {
                // Update recolors based on outgoing and incoming blocks
                let next = current 
                    + (window.last() == Some(&b'W')) as i32 
                    - (window.first() == Some(&b'W')) as i32;

                (next, min.min(next))
            }).1
    }
}

Tags: #rust #algorithms #counting

ответить
4

Сегодня мы решаем задачу 2924. Find Champion II

🏆 Задача:

В турнире n команд представлены как вершины DAG (ориентированного ацикличного графа). Если команда a сильнее команды b, это отображается направленным ребром от a к b. Требуется найти чемпиона турнира — вершину, из которой достижимы все остальные вершины. Если чемпиона нет или их несколько, вернуть −1.

😊 Идея:

В DAG вершина с отсутствующими входящими рёбрами (in_degree = 0) является источником. Если в графе ровно один источник, он становится кандидатом в чемпионы, так как из него достижимы все остальные вершины
(Нетривиальный момент: это утверждение не верно в общем случе, но в случае DAG его несложно доказать).
Если источников больше или ни одного, чемпиона не существует.

Сложность

Исходный код решения

impl Solution {
    pub fn find_champion(n: i32, edges: Vec<Vec<i32>>) -> i32 {
        let mut in_degree = vec![0; n as usize];

        // Calculate in-degrees for each node
        for e in &edges {
            in_degree[e[1] as usize] += 1;
        }

        // Identify the potential champion
        let mut champion = -1;
        let mut n_champions = 0;

        for (node, &degree) in in_degree.iter().enumerate() {
            if degree == 0 {
                champion = node as i32;
                n_champions += 1;
            }
        }

        // There must be exactly one node with in-degree 0
        if n_champions == 1 {
            champion
        } else {
            -1
        }
    }
}

1 ответ
3

Очередная наша задача — 2579. Count Total Number of Colored Cells, как ни странно, красиво решается на шахматной доске ☺.

📜 Описание задачи

Дана бесконечная двумерная сетка с неокрашенными клетками. В течение n минут выполняются следующие действия:

Необходимо вычислить количество окрашенных клеток после n минут.

🧠 Идея

Если рассмотреть процесс закрашивания клеток на шахматной доске, можно увидеть, что в момент n окрашенные клетки образуют два наложенных квадрата:

Сумма площадей этих двух квадратов и дает общее количество окрашенных клеток.

chess-pattern-s.png

🚀 Детали подхода

Применяем формулу: Total = n²+(n−1)²

⏳ Асимптотика

💻 Исходный код

impl Solution {
    pub fn colored_cells(n: i32) -> i64 {
        let n = n as i64;
        n*n + (n-1)*(n-1)
    }
}

Tags: #rust #algorithms #math

ответить
3

Ссылка на задачу - 1780. Check if Number is a Sum of Powers of Three.

📌 Описание задачи

Дано число n. Нужно определить, можно ли представить его в виде суммы различных степеней тройки.

🔹 Пример:

💡 Идея

Рассмотрим представление n в троичной системе счисления:

Таким образом, задача сводится к поразрядной проверке числа в троичной системе счисления.

🚀 Детали подхода

Будем использовать рекурсию и деление числа на 3:

  1. База рекурсии: Если n == 0, то мы успешно разложили число, возвращаем true.
  2. Шаг рекурсии: Если n % 3 == 2, то n нельзя разложить, возвращаем false.
  3. Рекурсивный вызов: Проверяем n / 3, повторяя процесс.

⏱ Асимптотика

📝 Исходный код

impl Solution {
    pub fn check_powers_of_three(n: i32) -> bool {
        n == 0 || (n % 3 != 2 && Self::check_powers_of_three(n / 3))
    }
}

Tags: #rust #algorithms #math

ответить
3

Ссылка на задачу - 2161. Partition Array According to Given Pivot.
В данной задаче нам предстоит реализовать базовую подзадачу Быстрой сортировки, но с дополнительным требованием сохранения относительного порядка, отчего стандартные методы реализации Q-sort нас не будут устраивать ☹

📌 Описание задачи

Дан массив nums и число pivot. Требуется переставить элементы массива так, чтобы:

💡 Идея

Мы хотим разделить массив на три части, не создавая лишние структуры данных.
Вместо этого заполним результирующий вектор напрямую, обрабатывая массив в три прохода.

🛠️ Детали подхода

1️⃣ Первый проход: добавляем в результат все элементы < pivot.
2️⃣ Подсчет и второй проход: вычисляем количество вхождений pivot в массиве и добавляем pivot в результат pivot_count раз.
3️⃣ Третий проход: добавляем все элементы > pivot в результат.

Используем Vec::with_capacity(nums.len()), чтобы избежать лишних аллокаций.

📊 Асимптотика

💻 Исходный код

impl Solution {
    pub fn pivot_array(nums: Vec<i32>, pivot: i32) -> Vec<i32> {
        let mut result = Vec::with_capacity(nums.len());

        // First pass: Collect elements smaller than pivot
        result.extend(nums.iter().filter(|&&num| num < pivot));

        // Count occurrences of pivot
        let pivot_count = nums.iter().filter(|&&num| num == pivot).count();

        // Insert pivot elements
        result.extend(std::iter::repeat(pivot).take(pivot_count));

        // Third pass: Collect elements greater than pivot using into_iter() to take ownership
        result.extend(nums.into_iter().filter(|&num| num > pivot));

        result
    }
}

Tags: #rust #algorithms

1 ответ
3

Ссылка на задачу - 2570. Merge Two 2D Arrays by Summing Values.

📌 Описание задачи

Даны два отсортированных списка nums1 и nums2, где каждый элемент представлен в виде [id, value].
Нужно объединить их в один список, упорядоченный по id, при этом суммируя значения для совпадающих id.

💡 Идея

Так как оба списка уже отсортированы по id, можно пройтись по ним одновременно, сравнивая id и добавляя элементы в результат.
Такой метод позволяет решить задачу за O(n + m) без дополнительной сортировки.

🛠 Подробности подхода

  1. Используем два индекса i и j для итерации по nums1 и nums2.
  2. Сравниваем текущие id:
    • Если id1 < id2 → добавляем nums1[i] в результат, сдвигаем i.
    • Если id1 > id2 → добавляем nums2[j] в результат, сдвигаем j.
    • Если id1 == id2 → суммируем значения, добавляем результат, сдвигаем оба указателя.
  3. Добавляем оставшиеся элементы из nums1 и nums2, если таковые имеются.

Читать дальше →

ответить
3

Ссылка на задачу — 2460. Apply Operations to an Array.

📝 Описание задачи

Дан массив nums, состоящий из неотрицательных целых чисел. Нужно последовательно выполнить следующие операции:

💡 Идея

Решение можно выполнить за один проход, используя два указателя (read и write):

Такой подход позволяет изменять массив на месте, не используя дополнительную память.

📌 Детали подхода

  1. Используем два указателя (read и write):
    • read проходит по массиву.
    • write отслеживает следующую позицию для ненулевых чисел.

Читать дальше →

ответить
3

Ссылка на задачу — 873. Length of Longest Fibonacci Subsequence.

📌 Описание задачи

Дан монотонно возрастающий массив arr. Нужно найти длину самой длинной фибоначчиевой подпоследовательности, где каждые три последовательных элемента x, y, z удовлетворяют свойству: z = x + y

Если такой подпоследовательности нет, вернуть 0.

💡 Идея

📌 Подробности метода

  1. Перебираем z = arr[k], начиная с k = 2, так как нужны минимум 3 числа.
  2. Будем использовать два указателя (front и back) на arr[..k]:
    • front движется вперёд (x увеличивается).
    • back движется назад (y уменьшается).
  3. Сравниваем x + y и z:

Читать дальше →

1 ответ
3

Ссылка на задачу — 1524. Number of Sub-arrays With Odd Sum.

📌 Описание задачи

Дан массив целых чисел arr. Необходимо найти количество подмассивов с нечётной суммой.
Так как ответ может быть очень большим, его необходимо вернуть по модулю 10⁹+7.

💡 Идея

Вместо явного перебора всех подмассивов (O(N²)), можно следить за чётностью суммы префикса.
Ключевое наблюдение:

🛠 Детали подхода

  1. Следим за чётностью префиксной суммы, храня в prefix_parity (0 - чётная, 1 - нечётная).
  2. Считаем количество чётных (even_count) и нечётных (odd_count) префиксных сумм.
  3. Используем fold для итеративного обновления результата.
  4. Добавляем соответствующие значения к result:
    • Если prefix_parity чётный, к result прибавляем odd_count.
    • Если prefix_parity нечётный, к result прибавляем even_count.

⏳ Асимптотика

💻 Исходный код

impl Solution {
    pub fn num_of_subarrays(arr: Vec<i32>) -> i32 {
        const MODULO: i32 = 1_000_000_007;

        let (result, _, _, _) = arr.into_iter()
            .fold((0, 0, 0, 1), |(result, prefix_parity, odd_count, even_count), num| {
                match(prefix_parity + num) % 2 {
                    0 => // Even prefix → account subarrays from odd prefixes
                        ((result + odd_count) % MODULO, 0, odd_count, even_count + 1),
                    _ => // Odd prefix → account subarrays from even prefixes
                        ((result + even_count) % MODULO, 1, odd_count + 1, even_count),
                }
            });

        result
    }
}

Tags: #rust #algorithms #prefixsum

ответить
3

Ссылка на задачу — 2467. Most Profitable Path in a Tree.

📌 Описание задачи

Дано неориентированное корневое дерево с n узлами (нумерованными от 0 до n-1).

Нужно найти максимальный чистый доход Алисы при оптимальном выборе пути.

💭 Идея

Вместо раздельного запуска BFS для поиска пути Боба и последующего прохода динамического программирования по узлам дерева, мы решим задачу одним рекурсивным DFS-проходом.

Для каждого узла будем вычислять:

Читать дальше →

ответить
3

Ссылка на задачу — 889. Construct Binary Tree from Preorder and Postorder Traversal.

📌 Описание задачи

Нам даны прямой (preorder) и обратный (postorder) обходы бинарного дерева.
Необходимо восстановить дерево по этим обходам.

Основные свойства обходов:

💡 Идея

Для построения дерева используем рекурсивный подход, основанный на двух ключевых наблюдениях:

🔍 Детали подхода

  1. Используем итераторы Peekable<Iterator> для эффективного прохода по preorder и postorder.
  2. Берем значение из preorder и создаем новый узел.
  3. Рекурсивно создаем левое поддерево, если postorder пока не указывает на текущий корень.

Читать дальше →

ответить
3

Ссылка на задачу — 1028. Recover a Tree From Preorder Traversal.

📝 Описание задачи

Дано строковое представление бинарного дерева, полученное в порядке прямого обхода, где:

Например для следующего дерева, представление будет таким: 1-2--3---4-5--6---7

Необходимо восстановить бинарное дерево по этой строке и вернуть его корень.

💡 Идея

Читать дальше →

ответить
3

Ссылка на задачу – 1261. Find Elements in a Contaminated Binary Tree.

📝 Описание задачи

Дано двоичное дерево, в котором:

Значения всех узлов загрязнены (-1).
Нужно реализовать структуру FindElements, которая:

💡 Идея

Восстанавливать дерево не требуется!
Вместо этого мы вычисляем путь к узлу target, определяя его родителя и положение.

🔍 Детали подхода

  1. Поиск родителя (parent):

Читать дальше →

ответить
2

Ссылка на задачу — 2523. Closest Prime Numbers in Range.

📌 Описание задачи

Нам даны два целых числа left и right.
Нужно найти два ближайших простых числа num1 и num2 таких, что:

Если существует несколько пар с одинаковой разницей, выбрать пару с меньшим первым числом.
Если таких чисел нет, вернуть [-1, -1].

🧠 Идея

Будем просто итерироваться по парам соседних простых чисел в заданом диапазоне.
Но, так как простые близнецы (пары простых чисел, разница между которыми равна 2) встречаются довольно часто (их плотность примерно 1 / log²(n)) мы можем эффективно ввести условие раннего выхода, которое значительно улучшает среднюю производительность алгоритма.

🔍 Подход

  1. Обработка граничных случаев:
    • Если left ≤ 2 и right ≥ 3, сразу возвращаем [2, 3].
  2. Перебор чисел в диапазоне:
    • Проверяем каждое число на простоту с помощью is_prime(n), работающей за O(√n).

Читать дальше →

ответить
3

Ссылка на задачу — 1980. Find Unique Binary String.
Кайфовая задачка для тех, кто не прогуливал лекции по мат. анализу ☺

📌 Описание задачи

Дан массив nums, содержащий n различных бинарных строк длины n.
Необходимо найти любую бинарную строку длины n, которая не содержится в nums.

💡 Идея

Используем диагонализацию Кантора:

🔍 Подробности подхода

  1. Итерируемся по индексам 0..n.
  2. Берем i-й символ i-й строки.
  3. Инвертируем его ('0' → '1', '1' → '0').
  4. Собираем новые символы в строку и возвращаем её.

📊 Асимптотика

Визуальный пример

🦀 Исходный код

impl Solution {
    pub fn find_different_binary_string(nums: Vec<String>) -> String {
        let n = nums.len();

        // Generate a new binary string by flipping the diagonal elements.
        (0..n)
            .map(|i| Self::inverse_char(nums[i].as_bytes()[i] as char))
            .collect()
    }

    fn inverse_char(c: char) -> char {
        match c {
            '0' => '1',
            '1' => '0',
            _ => unreachable!("Unexpected character: {}", c),
        }
    }
}

Tags: #rust #algorithms #math

ответить
2

Ссылка на задачу — 2965. Find Missing and Repeated Values.

📌 Описание задачи

Дан n×n целочисленный массив grid, содержащий числа от 1 до .
Одно число повторяется дважды (a), а одно отсутствует (b).
Нужно найти их.

💡 Идея

Мы можем использовать математические свойства сумм чисел:

Разница между ожидаемыми и фактическими значениями позволит выразить a и b через систему уравнений.

🚀 Детали подхода

  1. Вычисляем ожидаемую сумму и ожидаемую сумму квадратов для чисел от 1 до .
  2. Проходим по grid, вычисляя фактическую сумму и фактическую сумму квадратов.
  3. Находим промежуточные величины для системы уравнений:
    • (a - b) = sum_diff

Читать дальше →

ответить
3

Ссылка на задачу — 1415. The k-th Lexicographical String of All Happy Strings of Length n.

📝 Описание задачи

"Счастливая строка" – это строка длины n, состоящая только из символов ['a', 'b', 'c'], в которой нет двух одинаковых подряд идущих символов.
Нужно найти k-ю счастливую строку в лексикографическом порядке, либо вернуть "", если таких строк меньше k.

💡 Идея

Рассмотрим связь счастливых строк с двоичными строками.
Каждая счастливая строка:

Таким образом, двоичное представление k-1 почти полностью определяет структуру требуемой строки (без первого символа).
Мы можем использовать биты 0 и 1 из этого двоичного представления, чтобы выбирать между двумя допустимыми символами при итеративной генерации каждого следующего символа конкретной счастливой строки. 🚀

🔍 Детали подхода

  1. Определяем количество возможных строк с фиксированным первым символом:

Читать дальше →

ответить

Страница 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19