главная новое лучшее написать
неделя месяц год вечное
посты пользователи ответы
3

Задача - 1639. Number of Ways to Form a Target String Given a Dictionary

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

Дано: список строк words одинаковой длины и строка target.
Цель: определить, сколькими способами можно собрать строку target, следуя правилам:

💡 Идея

Мы можем использовать подход динамического программирования. Для быстрого обновления состояний ДП предварительно подсчитаем частоты символов для каждой позиции в words.

Формула ДП:

Пусть dp[i][j] — количество способов собрать первые i символов строки target, используя первые j-й позиции в строках words. Тогда:

dp[i][j] = dp[i][j−1] + dp[i−1][j−1]⋅freqj(target[i]]), где:

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

ответить
3

В следующей задаче - 2661. First Completely Painted Row or Column можно не симулировать в лоб, и за счёт этого сэкономить память при решении (хоть и не получится асимптотически лучше).

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

example-painting

Необходимо найти первый такой индекс i в массиве arr, при котором:

💡 Идея

Задачу можно переформулировать:

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

ответить
3

Задача на выходные - 2097. Valid Arrangement of Pairs

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

Нужно переставить заданные пары [starti,endi] так, чтобы получилось корректное расположение,
где для каждой пары i: endi−1=starti​. Гарантируется, что такое расположение существует.

Обзор решения 🛠

Для решения задачи используется алгоритм Хирхольцера, который позволяет построить Эйлеров путь (или цикл) в ориентированном графе. Основная идея — удалять рёбра во время обхода, что упрощает структуру данных и предотвращает повторное использование рёбер.

Ключевые шаги 🚀

  1. Построение графа:
    • Граф представляется в виде списка смежности (HashMap<i32, Vec<i32>>), где каждая вершина хранит список своих исходящих рёбер.
    • Параллельно вычисляются разницы степеней вершин (входящих и исходящих рёбер) для определения начальной вершины пути.
  2. Поиск начальной вершины:
    • Начальная вершина — это вершина с положительным балансом исходящих рёбер. Если таких нет, берётся любая вершина из входных данных.
  3. Итеративный DFS с удалением рёбер:
    • Вместо стандартного рекурсивного DFS используется итеративный подход с явным стеком. Это повышает эффективность памяти и скорость.
    • При посещении вершины рёбра удаляются из списка смежности, что гарантирует, что каждое ребро используется ровно один раз.

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

ответить
3

Задача: 2872. Maximum Number of K-Divisible Components

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

Дано неориентированное дерево с n узлами, пронумерованными от 0 до n−1. Также даны:
- массив рёбер edges, где каждое ребро связывает два узла,
- массив значений values, где значение values[i] связано с узлом i,
- число k.
- гарантируется, что сумма всех значений values кратна k

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

Идея 💡

Будем разбивать дерево на компоненты рекурсивно (DFS), начиная с произвольного узла.
Несложно показать, что родительская вершина должна быть в одной компененте со всеми дочерними, для которых сумма значений в соответствующем поддереве не делится на k.

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

  1. Построение графа:
    • Представляем дерево в виде списка смежности для удобного обхода.
  2. Обход дерева:

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

ответить
3

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

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

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

💡 Идея

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

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

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

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

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

ответить
3

Сегодня мы разберём задачу 916. Word Subsets.

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

Вам даны два массива строк words1 и words2.

Задача: найти все строки из words1, которые являются универсальными относительно всех строк из words2.

Условие универсальности:
Строка a из words1 универсальна, если для каждой строки b из words2 строка b является подмножеством строки a (Подмножество строки: строка b является подмножеством строки a, если каждая буква в b встречается в a как минимум столько же раз).

Пример:

💡 Идея

Для эффективного решения задачи:
- Определим максимальное количество вхождений каждой буквы по всем строкам из words2.
- Для каждой строки из words1 проверим, удовлетворяет ли она этим требованиям.

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

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

ответить
3

Наша очередная задача - 1930. Unique Length-3 Palindromic Subsequences.

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

Дана строка s. Необходимо определить количество уникальных палиндромов длины 3, которые являются подпоследовательностями строки.

Подпоследовательность — это строка, полученная из исходной строки удалением некоторых (возможно, нуля) символов без изменения их порядка. Например, для строки "abcde" строка "ace" является подпоследовательностью.

Палиндром — это строка, которая читается одинаково в прямом и обратном направлениях.

💡 Идея

Основная идея заключается в том, что палиндром длины 3 определяется первыми и последними символами, которые совпадают, а также любым допустимым символом посередине.
Мы можем эффективно отслеживать такие пары (первый и последний символы) с помощью битового массива (bitset), что позволяет минимизировать использование памяти.

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

  1. Массивы частот:
    • prefix_frequency: хранит частоты символов слева от рассматриваемого.
    • suffix_frequency: хранит частоты символов справа от рассматриваемого.

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

ответить
3

Сегодня нам предстоит решить задачу 2577. Minimum Time to Visit a Cell In a Grid.

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

💡 Идея

Задача сводится к поиску кратчайшего пути с учётом времени открытия ворот в каждой ячейке. Можно представить задачу как динамический граф, где вершины — это пары (время, ячейка), а рёбра — это возможные переходы между ячейками. Вместо того чтобы хранить весь граф, мы динамически вычисляем возможные переходы из посещаемых вершин. Вершины будем перебирать в порядке времён достижимости ячейки (как в алгоритме Дейкстры).

🔑 Подход к решению

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

ответить
3

Задача, что мы рассмотрим сегодня - 2948. Make Lexicographically Smallest Array by Swapping Elements

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

Лексикографический порядок: Массив a меньше массива b, если на первой позиции i, где они различаются, a[i] < b[i].

💡 Идея:

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

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

  1. Сортировка индексов: На первом шаге создаём массив sorted_indices, заполняя его значениями [0, 1, ..., n-1]. Затем сортируем этот массив по значениям массива nums, чтобы определить относительный порядок элементов.

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

ответить
3

Сегодня нам предстоит решить задачу 1792. Maximum Average Pass Ratio.

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

У нас есть школа, где классы проводят итоговые экзамены. Каждый класс описывается массивом [pass_i,total_i], где:

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

2 ответа
3

На этот раз наша задача выглядит заковыристо - 2982. Find Longest Special Substring That Occurs Thrice II.

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

Необходимо найти длину самой длинной "особенной" подстроки, которая встречается в строке хотя бы три раза. Если такой подстроки нет, вернуть -1.

"Особенная" подстрока — это подстрока, содержащая один и тот же символ.

😊 Идея

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

🚀 Подход

  1. Перебираем все строчные английские буквы ('a' до 'z').
  2. Для каждой буквы:
    • Находим все её подряд идущие сегменты (например, для 'aaaabbaab' сегменты: [4,2], [2,1] для 'a' и 'b').
    • Сортируем длины сегментов по убыванию.
    • Вычисляем максимальную возможную длину "особенной" подстроки, встречающейся как минимум три раза, используя метод get_triple_length.

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

4 ответа
3

Ссылка на задачу – 3105. Longest Strictly Increasing or Strictly Decreasing Subarray.

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

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

🤔 Идея

Разбить массив на группы (чанки) по непрерывной монотонности (либо возрастающей, либо убывающей).
Для каждой группы вычислить её длину, а затем выбрать максимальное значение среди всех групп.

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

  1. Разбиение на чанки:
    Используем метод chunk_by для разбиения массива:
    • Для строго возрастающей последовательности используем сравнение a < b.
    • Для строго убывающей последовательности используем сравнение a > b.
  2. Вычисление максимальной длины:
    • Для каждого набора чанков вычисляем длину каждой группы, выбираем максимальную длину для возрастающих и убывающих групп.
  3. Результат:
    • Возвращаем максимум между максимальной длиной возрастающей и максимальной длиной убывающей последовательности.

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

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

impl Solution {
    pub fn longest_monotonic_subarray(nums: Vec<i32>) -> i32 {
        // Group strictly increasing segments using chunk_by
        let max_increasing_len = nums.chunk_by(|a, b| a < b)
            .map(|c| c.len()).max().unwrap_or(0);

        // Group strictly decreasing segments using chunk_by
        let max_decreasing_len = nums.chunk_by(|a, b| a > b)
            .map(|c| c.len()).max().unwrap_or(0);

        max_increasing_len.max(max_decreasing_len) as i32
    }
}

Tags: #rust #algorithms #iterators

1 ответ
3

Задача на сегодня 3152. Special Array II.

📝 Условие:

🧠 Идея:

💡 Подход:

  1. Префиксная сумма:
    • Создаём массив prefix_count, где prefix_count[i] хранит количество пар соседних элементов с разной чётностью от начала массива до индекса i.
    • Заполняем его за O(n) в одном проходе.
  2. Обработка запросов:
    • Для каждого запроса [from, to] считаем количество таких пар в диапазоне через разность: prefix_count[to] - prefix_count[from].

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

ответить
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

Задача на сегодня 1368. Minimum Cost to Make at Least One Valid Path in a Grid - достаточно стандартная вариация лабиринта с бесплатными переходами.

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

У нас есть поле размером m×n, где каждая клетка содержит указание направления движения. Необходимо найти минимальную стоимость перехода из левого верхнего угла (0, 0) в правый нижний угол (m−1,n−1).

Каждая клетка указывает направление движения:

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

💡 Идея

Поле можно рассматривать как ориентированный граф, где клетки являются вершинами, а направления задают ребра. Наша цель — найти минимальную стоимость пути из начальной клетки в конечную. Для этого используется модифицированный BFS с двумя очередями, где приоритет отдается движениям без изменения направления.

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

  1. Две очереди:

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

ответить
3

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

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

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

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

💡 Идея

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

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

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

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

ответить
3

Ссылка на задачу — 3169. Count Days Without Meetings.

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

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

💡 Идея

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

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

1️⃣ Сортируем встречи по начальной дате.
2️⃣ Проходим по списку встреч, отслеживая next_free (следующий свободный день).
3️⃣ Подсчитываем разрывы между next_free и началом следующей встречи.
4️⃣ Обновляем next_free после каждой встречи, сдвигая его на день после её окончания.
5️⃣ Добавляем свободные дни после последней встречи.

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

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

impl Solution {
    pub fn count_days(days: i32, mut meetings: Vec<Vec<i32>>) -> i32 {
        meetings.sort_unstable_by_key(|meet| meet[0]);

        let (next_free, free_count) = meetings.into_iter()
            .fold((1, 0), |(next_free, free_count), meet| {
                let [start, end] = meet[..2] else { unreachable!("bad meet format") };
                let gap = (start - next_free).max(0);
                let next_free = next_free.max(end + 1);
                (next_free, free_count + gap)
        });

        free_count + (days - next_free + 1).max(0)
    }
}

Tags: #rust #algorithms #counting

ответить
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

Сегодня у нас интересная задача на битовые манипуляции – 2429. Minimize XOR.

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

Дано два положительных числа num1 и num2. Нужно найти число x, такое что:

💡 Идея

Для минимизации XOR мы
- Стремимся сохранить как можно больше старших битов из числа num1, так как они оказывают наибольшее влияние на минимизацию результата.
- Если остаются неиспользованные биты, мы добавляем младшие биты, чтобы завершить формирование числа x с требуемым количеством установленных битов.

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

  1. Подсчёт установленных битов:
    • Используем метод count_ones, чтобы подсчитать количество установленных битов в числе num2.
  2. Сохранение старших битов:
    • Проходим по битам num1 с самого старшего до младшего.
    • Если бит установлен, включаем его в результат и уменьшаем счётчик оставшихся битов.

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

1 ответ
3

Ссылка на задачу – 1726. Tuple with Same Product.

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

Дан массив nums из различных положительных чисел. Нужно вернуть количество кортежей (a, b, c, d), таких что произведение a * b равно произведению c * d, при условии, что все элементы кортежа различны.

💡 Идея

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

  1. Подсчет в HashMap:
    • Используем два вложенных цикла для перебора всех уникальных пар (i, j) с условием i < j и вычисляем их произведение.
    • Результаты произведений сохраняем в HashMap, где ключ — это само произведение, а значение — количество его вхождений.
  2. Расчет кортежей:
    • Для каждого произведения с частотой больше 1, добавляем в итоговый результат значение
      4 * frequency * (frequency - 1).
  3. Возврат результата:

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

1 ответ
3

Первая задача в этом году - 1422. Maximum Score After Splitting a String несложная, и интересно решить её за один проход по массиву.

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

Дана бинарная строка, состоящая из символов 0 и 1.
Требуется найти максимальный результат разбиения строки на две непустые подстроки.
Результат определяется как:

💡 Идея

Для эффективного решения задачи:

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

  1. Формула результата: Для разбиения в точке i:
    • Result = zero_count + (total_ones - ones_count)
      , где:
      • zero_count – число нулей слева

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

ответить
3

Сегодня нас опять радует задачка на методы динамического программирования - 2466. Count Ways To Build Good Strings.

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

Нам нужно подсчитать количество "хороших строк", длина которых находится в диапазоне [low, high].
Хорошая строка создаётся из пустой строки путём выполнения следующих операций:

Результат может быть очень большим, поэтому необходимо вернуть его по модулю 10⁹+7.

💡 Идея

Для решения задачи мы используем динамическое программирование.
Каждое состояние dp[length] хранит количество способов построить строку длины length.
Постепенно вычисляя значения для всех длин от 1 до high, мы получаем итоговый результат.

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

  1. Инициализация:
    • Создаём массив dp длиной high+1, где dp[length] будет содержать количество способов построить строку длины length.
    • Базовый случай: dp[0] = 1, так как существует ровно один способ создать пустую строку.

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

ответить
3

Сегодня рассмотрим достаточно простое решение задачи 2779. Maximum Beauty of an Array After Applying Operation.

Условие 📋

Дан массив nums и целое неотрицательное число k. Разрешается заменить каждый элемент массива (не более одного раза) любым числом из диапазона [nums[i]−k,nums[i]+k]. Требуется найти максимальную длину подпоследовательности массива, состоящей из одинаковых элементов (это называется "красота массива").

Идея 💡

Фактически задача сводится к нахождению наибольшего подмножества массива, все элементы которого укладываются в интервал длины 2×k. Чтобы эффективно найти такой диапазон, можно использовать метод скользящего окна по предварительно отсортированному массиву.

Подход 🛠️

  1. Сортировка массива: Упорядочиваем массив, чтобы элементы, которые могут принадлежать одному диапазону, оказались рядом.
  2. Скользящее окно: Используем два указателя (l и r) для определения максимального диапазона, удовлетворяющего условию nums[r]−nums[l]≤2×k.
  3. Подсчёт длины диапазона: На каждом шаге обновляем результат как максимум текущей длины окна r−l.

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

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

impl Solution {
    pub fn maximum_beauty(nums: Vec<i32>, k: i32) -> i32 {
        // Create a mutable copy of nums and sort it
        let mut sorted_nums = nums.clone();
        sorted_nums.sort_unstable();

        let mut max_beauty = 0;
        let mut right = 0;

        // Iterate over each number in the sorted array
        for left in 0..sorted_nums.len() {
            // Expand the right pointer as long as the difference is within the allowed range
            while right < sorted_nums.len() && sorted_nums[right] <= sorted_nums[left] + 2 * k {
                right += 1;
            }
            // Update the maximum beauty based on the current window size
            max_beauty = max_beauty.max((right - left) as i32);
        }

        max_beauty
    }
}

ответить
3

На нашей новой задаче 2415. Reverse Odd Levels of Binary Tree есть повод продемонстировать продвинутые методы Rust работы с итераторами (std::iter::successors & std::iter::zip), а также "непристойную" работу c реф-каунт ячейками :(

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

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

💡 Идея

Мы адаптируем BFS для обхода дерева по уровням. На каждом уровне проверяется, нужно ли инвертировать порядок значений (для нечетных уровней). С помощью вспомогательной функции формируются следующие уровни дерева.

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

  1. Вспомогательная функция next_level:
    • Формирует следующий уровень дерева, собирая всех левых и правых потомков текущих узлов.
  2. Завершение обработки:
    • Проверка, что текущий уровень является листовым, выполняется через условие nodes[0].borrow().left.is_none().
    • При достижении уровня листьев обработка завершается.
  3. Обход уровней с помощью std::iter::successors:
    • Используется функциональный подход для последовательного формирования уровней дерева. Итератор автоматически останавливается при достижении листового уровня.

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

ответить
3

Очередная наша задача - 2593. Find Score of an Array After Marking All Elements. Ну и так как наша цель не просто решать, а показывать имплементацию разных техник, то воспользуемся-ка мы идеей битового множества (его в стандартную библиотеку Rust еще "не подвезли", так что и операции имплементируем сами).

Задача 🧩

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

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

Необходимо вернуть итоговое значение score.

Идея 💡

В данной задаче нужно эффективно следовать указанным правилам. Чтобы сделать это:

Подход 🚀

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

ответить

Страница 1 2 3 4