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

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

Задача 🧩

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

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

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

Идея 💡

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

Подход 🚀

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

ответить
3

Сегодня мы решаем задачу 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
        }
    }
}

ответить
3

Сегодня на очереди задача 2825. Make String a Subsequence Using Cyclic Increments.

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

Даны две строки str1 и str2. Нужно определить, можно ли сделать str2 подпоследовательностью строки str1, выполнив не более одной операции циклического увеличения произвольного набора символов в str1.
Циклический сдвиг означает, что 'a' становится 'b', 'b''c', ..., 'z''a'.

Идея решения 💡

Задача почти идентична проверке подпоследовательности в строке. Единственное отличие — сравнение символов становится чуть сложнее из-за необходимости учитывать циклический сдвиг.
Мы выделяем проверку совпадения символов в отдельный метод, а в остальном используем стандартный алгоритм проверки подпоследовательности.

Реализация подхода 🚀

  1. Используем два итератора для последовательного прохода по символам строк.
  2. Для сравнения символов применяем отдельную функцию, учитывающую как прямое совпадение, так и циклический сдвиг.
  3. При совпадении текущего символа строки str2 с символом из str1, переходим к следующему символу в str2.
  4. Если все символы str2 найдены в str1 в правильном порядке, возвращаем true, иначе — false.

Сложность алгоритма 📊

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

ответить
5

Ответ спасен из Яндекс.Кью

Это, внезапно, одна из лучших научно-популярных книжек из тех, что я читал за последние годы. Тема, казалось бы, узкая (о некотором античном механизме, найденном в останках кораблекрушения, и попытках разгадать, для чего он служил и как был устроен), но автор настолько фантастически и разносторонне образован, и настолько системно мыслит, что за пару абзацев мимоходом меняет читателю представление о целых масштабных областях.

Чтобы не быть голословным: все мы со школы помним про "бронзовый век", да? Не знаю, как вы, а я с тех пор его так и представлял как-то очень упрощенно. Были люди в шкурах и всё такое, потом научились обработке металлов, люди с бронзовыми мечами легко выносили людей с каменными или даже с медными топорами, ну и понеслась. Так вот, как известно, бронза -- сплав меди с оловом. То ли первая, то ли одна из первых цивилизаций бронзового века, Эгейская (3200 до н.э.), выплавляла бронзу на Кипре, где были удобные для разработки месторождения меди, а олово для этого доставлялось, тадам, из Англии. Представьте себе размеры и сложность необходимых для этого торговых путей и общества в целом. Вот вам и пещерные люди.

Отличие хороших книжек от интернета, если кому-то нужно его доказывать, иллюстрируется тем фактом, что из википедии, например, понять это невозможно, даже если читать именно статью "Бронзовый век", просто не поймешь, на что смотреть.

Или вот другой факт: оказывается, императорская Япония вполне себе разрабатывала ядерное оружие и в 1945 году даже приступила к строительству установки по обогащению урана, чуть-чуть не успели, в общем. Как так получается, что я об этом впервые читаю в книжке, вообще совершенно не об этом написанной?!

Ещё очень радует, что автор, когда ему что-то непонятно, в отличие от большинства своих коллег, не стесняется так и писать: непонятно. После распространенного в научпопе сциентистского высокомерия это освежает. Почему античная цивилизация, дойдя до паровой машины и точных механических калькуляторов, вместо вступления в индустриальную эру решила погибнуть, непонятно. Имеющиеся разъяснения выглядят как средневековое "чеснок исцеляет благодаря своей исцелительной силе", исчерпывающего и убедительного объяснения нет.

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

ответить
3

Спасибо загадочному пользователюleetcoder, здесь опять есть какая-то жизнь. По такому случаю попробуем сюда писать в формате классического web log, вдруг получится не бросить?

Прикольная статья про силу воли и выгорание. Как всегда на lesswrong, длинновато и напоминает домашнюю философию, но основная мысль крайне простая и что-то в ней есть.

У каждого человека есть "бюджет" силы воли. Внутренний нарратор-планировщик, он же "Система 2", когда вы хотите сделать что-то неприятное, берёт кредит из этого "бюджета". Когда в вашей жизни происходит что-то приятное (приятное на базовом, бессознательном уровне), связанное с предыдущими решениями планировщика, бюджет пополняется. Если в бюджете нет средств, вы "выгорели", у вас "не хватает силы воли". Важная часть мысли состоит в том, что "приятное" определяется бессознательно, "системой 1". Например, вы очень любите мороженое; съесть мороженое и заработать $1000 могут оказаться одинаково ценными пополнениями бессознательного бюджета, хотя объективно первое примерно в тысячу раз дешевле. Это позволяет управлять "бюджетом" на сознательном уровне, решая оптимизационную задачу, и помогать другим в том же. Например, взрослые люди, как правило, недохвалены: если они делают свою работу профессионально, затратив на это немало усилий, в том числе и волевых, то это "само собой разумеется".

ответить
5

Наверняка у вас были книжки о математике/программированию, которыми вы зачитывались в подростковом возрасте?

Из тех, которые запомнились мне:
"Математические новеллы", Гарднера и "Алиса в стране смекалки" Рэймонда Смаллиана - обе могу порекомендовать как взрослым, так и детям. #books #math

4 ответа
3

Сегодня у нас еще одна задача на аккуратное манипулирование индексами 2337. Move Pieces to Obtain a String.

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

Даны две строки start и target длины n, содержащие символы 'L', 'R' и '_'.

Идея 🧠

Задача сводится к тому, чтобы проверить, совпадают ли позиции и направления символов 'L' и 'R' в двух строках с учётом их ограничений на движение. Мы используем итерацию по строкам одновременно, отслеживая доступные символы 'L' и 'R' через счётчики.

Подход 🛠️

  1. Используем метод as_bytes(), чтобы быстро перебрать символы в виде байтов.
  2. Одновременно проходим по обеим строкам:
    • Если видим 'L' в target, увеличиваем счётчик доступных 'L'.
    • Если видим 'L' в start, проверяем, есть ли доступный 'L', и уменьшаем счётчик.

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

ответить
5

Итак, я нагло спарсил notq(спасибо @finder за отсутствие антифрода) и решил посмотреть топовые статьи по голосам пользователей. Текущий топ выглядит так:

| rating | link_title |
|---------:|:----------------------------------------------------------------------------------------|
| 45 | Что здесь происходит - notq |
| 31 | Совет молодому руководителю в IT - notq |
| 16 | Планы на будущее - notq |
| 16 | Космическая интуиция - notq |
| 13 | Печенье "Юбилейное" - notq |
| 11 | Глубокая мысль - notq |
| 10 | Как рассчитывать цену производных финансовых инструментов - notq |
| 9 | Performing productivity at Google: It’s All Bullshit - notq |
| 9 | Кардиологи и китайские грабители - notq |
| 8 | Интервью с директором советского продуктового магазина - notq |

Наиболее рейтинговым автором стал(кто бы сомневался) @robot-q-reposter. За ним идут @finder, @notq и @1e9y.

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

2 ответа
3

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

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

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

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

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

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

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

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

ответить
5

Год назад, когда Карпатый присоединился к OpenAI, я удивлялся, как они умудряются нанимать таких людей на такие роли. Вроде как он у них занимался тем же, чем у нас условные миддлы занимаются. Если кто вдруг не знает, до этого он был директором по AI в Тесла, и вообще очень известный в индустрии человек со своей страничкой в Википедии, десятками тысяч звезд на Гитхабе и т.п.

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

Так вот вопрос, как они умудрились собрать команду, в которой Андрей выглядит "ниже ожиданий", и которая силами 200-300 человек регулярно унижает остальной мир, включая фаанги? У меня есть единственное предположение - они тупо платят втрое больше других, но при этом хорошо знают, кому, и потому перекупают у остальных действительно ключевых людей. Но даже это весьма непросто устроить.

7 ответов
3

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

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

💡 Идея

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

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

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

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

Сегодня нам предстоит несложная задача - 2182. Construct String With Repeat Limit. Но технически она получилась муторной - требует от программиста очень аккуратного подхода к себе :)

Задача 📜

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

Подход 🚀

  1. Подсчёт частоты символов:
    • Используем массив размера 256, чтобы подсчитать количество вхождений каждого байта (символа).
  2. Жадный выбор символов:
    • Обходим пространство символов (0–255), начиная с самого большого.
    • Добавляем текущий символ в результат до repeat_limit раз или пока его количество не исчерпается.
    • Если нужно "разорвать" последовательность, вставляем следующий по величине символ, уменьшая его количество.
  3. Эффективный поиск следующего символа:
    • Вспомогательная функция find_last_valid_index ищет ближайший допустимый символ с ненулевой частотой, используя знание о текущем символе как ускоряющую подсказку.

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

2 ответа
5

Aphantasia

finder, 23-01-2024

Aphantasia - состояние, при котором человек, воображая что-то, не формирует при этом зрительные образы.

Многие носители афантазии описывают свои ощущение от открытия, что это, оказывается, не универсально, примерно так (цитирую по памяти):

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

У меня у самого афантазия. Я не знал о том, что у меня нет чешуйчатого хвоста, до 30+ лет, и абзац выше очень похож на мои собственные ощущения от этого открытия.

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

Объясню для (нормальных в этом смысле) айтишников, о чем речь. Когда я говорю "я представил себе дерево с оранжевой кроной, на котором висят качели, сделанные из старой шины", я не вижу перед собой дерево, ни в каком смысле слова "вижу"; у меня просто нет отдельной копии 2d визуального буфера под такую задачу. Вместо этого я делаю совсем другое, а именно, погружаю в оперативную память указатели на понятия "дерево", "оранжевая крона", "качели", "старая шина" и связи между ними. Это позволяет мне дальше производить, в общем, почти те же операции с тем, что я "представил", что и нормальные люди, за исключением некоторых специальных случаев вроде рисования. Думаю, именно из-за этого я могу рисовать мультяшки, пиксельарт и карикатуры, но не научился рисовать сколько-нибудь реалистично, хотя пробовал.

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

8 ответов
3

Наступление зимы отметим разбором простой задачи 1346. Check If N and Its Double Exist.

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

Дан массив целых чисел arr. Нужно определить, существуют ли такие индексы i и j, что:
- i≠j,
- arr[i]=2⋅arr[j].

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

Решение использует два простых прохода по массиву:

  1. Первый проход:
    • Создаем хеш-таблицу, где для каждого элемента записываем количество его удвоенных значений.
  2. Второй проход:
    • Проверяем, существует ли текущий элемент в хеш-таблице.
    • Для нуля (0) дополнительно проверяем, встречается ли он в массиве как минимум дважды (так как 2⋅0=0).

Временная сложность ⏱️

Пространственная сложность 📦

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

use std::collections::HashMap;

impl Solution {
    pub fn check_if_exist(arr: Vec<i32>) -> bool {
        let mut double_map = HashMap::new();

        // Populate the map with counts of doubled values
        for &num in &arr {
            *double_map.entry(2 * num).or_insert(0) += 1;
        }

        // Check for the required condition
        for &num in &arr {
            if num == 0 {
                // Special case for 0 (2 * 0 == 0)
                if *double_map.get(&0).unwrap_or(&0) > 1 {
                    return true;
                }
            } else if double_map.get(&num).is_some() {
                return true;
            }
        }

        false
    }
}

1 ответ
3

Сегодня чуток похулиганим и предоставим переоптимизированное решение для задачи 2554. Maximum Number of Integers to Choose From a Range I. В реальном интервью такое могут потребовать лишь на уровне идеи, но нам интересно запрограммировать самим :)

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

Необходимо выбрать максимально возможное количество чисел из диапазона [1,n], при этом соблюдая ограничения:
- Числа из списка banned выбирать нельзя.
- Каждое число можно использовать не более одного раза.
- Сумма выбранных чисел не должна превышать maxSum.

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

Идея решения 💡

Предвычисляем суммы запрещённых чисел и используем двоичный поиск, чтобы найти максимальное k, для которого сумма допустимых чисел в диапазоне [1,k] не превышает maxSum. Это позволяет эффективно учитывать ограничения и избежать лишних вычислений.

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

  1. Сортировка и удаление дубликатов:
    • Сортируем массив banned и удаляем повторяющиеся элементы.
  2. Предвычисление кумулятивных сумм:
    • Создаем массив ban_sums, где на позиции i содержится сумма первых i запрещённых чисел. Это позволяет быстро вычислять сумму запрещённых чисел до любого предела.

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

ответить
3

Сегодня мы решаем задачу 3243. Shortest Distance After Road Addition Queries I

Постановка

В задаче требуется вычислить кратчайший путь от города 0 до города n-1 после каждой из последовательных добавлений новых дорог в граф. Изначально города соединены цепочкой дорог, и после каждой операции добавляется новая односторонняя дорога между двумя городами. Необходимо после каждой операции находить кратчайшее расстояние от города 0 до города n-1.

🔍 Идея

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

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

  1. Инициализация графа и расстояний:
    • Сначала создаем список смежности succ, который представляет дороги между городами, инициализируем его так, чтобы города были соединены цепочкой (каждый город соединен с следующим).
    • Массив dist инициализируется так, что расстояние от города 0 до города i равно i (для начальной цепочки).
  2. Обработка запросов:
    • Для каждого запроса добавляется новая дорога между городами u и v. После этого запускается BFS с города v для обновления кратчайших расстояний до всех достижимых городов.

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

ответить
3

Новый день - новая задача 2109. Adding Spaces to a String.

Условие 🧩

Дана строка s и массив индексов spaces. Нужно добавить пробелы перед символами строки, расположенными по данным индексам, и вернуть новую строку. Например, для s = "EnjoyYourCoffee" и spaces = [5, 9] результатом будет "Enjoy Your Coffee".

Если решать абы как, то можно и в ней запутаться в индексах. Мы же будем делать все максимально просто.

Идея решения 🧠

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

Подход 🔍

  1. Предварительно выделяем память для результирующей строки с помощью String::with_capacity, учитывая длину строки и количество пробелов.
  2. Проходим по массиву индексов spaces:
    • Добавляем в результат подстроку от предыдущей позиции до текущего индекса.
    • Добавляем пробел.
  3. После цикла добавляем оставшуюся часть строки.
  4. Возвращаем итоговую строку.

Анализ сложности 📊

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

impl Solution {
    pub fn add_spaces(s: String, spaces: Vec<i32>) -> String {
        let mut result = String::with_capacity(s.len() + spaces.len()); // Pre-allocate capacity for efficiency
        let mut word_pos = 0;

        for &space_pos in &spaces {
            let space_pos = space_pos as usize; // Convert i32 to usize for indexing
            result.push_str(&s[word_pos..space_pos]); // Add the substring
            result.push(' '); // Add the space
            word_pos = space_pos;
        }

        result.push_str(&s[word_pos..]); // Add the remaining substring
        result
    }
}

2 ответа
3

Сегодня разберём ещё одну простую задачу 1455. Check If a Word Occurs As a Prefix of Any Word in a Sentence.

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

Дана строка sentence, состоящая из слов, разделённых пробелами, и строка searchWord. Нужно определить индекс (считаем с 1), где searchWord является префиксом какого-либо слова в sentence. Если такого слова нет — вернуть -1.

Решение 🛠️

Идея 💡

Задача сводится к простому проходу по словам строки. Мы должны проверить каждое слово: начинается ли оно с searchWord. Возвращаем индекс первого подходящего слова.

Алгоритм 🚀

  1. Разделяем строку sentence на слова с помощью метода split_whitespace, который возвращает ссылки на части исходной строки.
  2. Проходим по словам с их индексами через enumerate.
  3. Для каждого слова проверяем, начинается ли оно с searchWord с помощью метода starts_with.
  4. Если находим соответствие, возвращаем индекс (преобразуем его в формат 1-based). Если совпадений нет, возвращаем -1.

Анализ Сложности 📊

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

impl Solution {
    pub fn is_prefix_of_word(sentence: String, search_word: String) -> i32 {
        // Split the sentence into words using whitespace as a delimiter
        let words = sentence.split_whitespace();

        // Iterate through the words with their indices
        for (index, word) in words.enumerate() {
            // Check if search_word is a prefix of the current word
            if word.starts_with(&search_word) {
                return (index + 1) as i32; // Convert 1-based index to i32 and return
            }
        }

        -1 // Return -1 if no prefix match is found
    }
}

4 ответа
5

Страны и их процентики

В "остальное" вошли США, Германия, Израиль и почему-то Китай. Какие выводы можно сделать, кроме "нотка стронк", я не знаю, просто хотел показать )

4 ответа
3

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

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

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

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

2 ответа
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

Очередная задача: 2290. Minimum Obstacle Removal to Reach Corner.

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

Дана двумерная матрица grid размером m x n, где каждая клетка может быть либо пустой (0), либо препятствием (1), которое можно удалить. Задача заключается в том, чтобы найти минимальное количество препятствий, которые нужно удалить, чтобы пройти из верхнего левого угла (0, 0) в нижний правый угол (m-1, n-1), передвигаясь только по пустым клеткам или удаляя препятствия.

🔑 Идея

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

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

  1. Инициализация: Мы создаем две очереди: front и back. Во front помещаем клетки, которые можно пройти без удаления препятствий, а в back — клетки, для которых потребуется удалить препятствие.
  2. Поиск в ширину (BFS):
    • Начинаем с верхнего левого угла и устанавливаем расстояние для этой клетки в 0 (т.е. препятствий еще не удалено).
    • Если клетка пустая (значение 0), мы добавляем её в front. Если клетка — препятствие (значение 1), то в back.

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

ответить
3

Сегодня решаем задачу 2054. Two Best Non-Overlapping Events. Будем закреплять двоичный поиск ;)

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

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

💡 Идея

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

🛠️ Подход

  1. Сортировка событий: По end_time в порядке убывания.
  2. Предобработка максимальных ценностей: Создаём массив max_vals с накопленной максимальной ценностью событий (справа-налево).
  3. Итерация и поиск:
    • Для каждого события находим первое, заканчивающееся раньше его, через двоичный поиск.
    • Суммируем ценности текущего события и накопленной максимальной ценности по найденному индексу, обновляя общий максимум.

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

ответить
3

Сегодняшняя задача 1475. Final Prices With a Special Discount in a Shop решается с помощью стандартного стека, но интересно и нестандартно выглядит мотивация его использования.

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

У вас есть массив цен prices, где prices[i] — это цена i-го товара. Если вы покупаете товар i, вы можете получить скидку, равную цене первого товара с индексом j>i, для которого выполняется условие prices[j] ≤ prices[i]. Если такого товара нет, скидка не применяется. Требуется вернуть массив, где каждая позиция показывает финальную цену с учётом скидки.

Идея 🤔

Подход 🚀

  1. Создаём стек discount_candidates, чтобы хранить индексы товаров, ожидающих применения скидки.
  2. Итерируем по массиву prices:
    • Пока верхний элемент стека соответствует условию скидки (цена товара в стеке ≥ текущей цене), применяем скидку и удаляем элемент из стека.

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

ответить

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