Очередная наша задача - 2593. Find Score of an Array After Marking All Elements. Ну и так как наша цель не просто решать, а показывать имплементацию разных техник, то воспользуемся-ка мы идеей битового множества (его в стандартную библиотеку Rust еще "не подвезли", так что и операции имплементируем сами).
Задача 🧩
Дан массив положительных целых чисел nums
. Ваша цель — получить максимальное значение score
, выполняя следующие действия:
- Выберите наименьший немаркированный элемент массива (при равенстве — элемент с меньшим индексом).
- Добавьте значение этого элемента к
score
.
- Пометьте выбранный элемент и его двух соседей (если они существуют).
- Повторяйте, пока все элементы не будут помечены.
Необходимо вернуть итоговое значение score
.
Идея 💡
В данной задаче нужно эффективно следовать указанным правилам. Чтобы сделать это:
- (а) Мы отсортируем индексы массива nums по значениям, чтобы обрабатывать элементы в правильном порядке, начиная с наименьших.
- (б) Используем битовое множество (
Vec<u128>
) для компактного представления состояния "помечен" для элементов массива.
Подход 🚀
Читать дальше →
ответить
Сегодня мы решаем задачу 2924. Find Champion II
🏆 Задача:
В турнире n
команд представлены как вершины DAG (ориентированного ацикличного графа). Если команда a
сильнее команды b
, это отображается направленным ребром от a
к b
. Требуется найти чемпиона турнира — вершину, из которой достижимы все остальные вершины. Если чемпиона нет или их несколько, вернуть −1
.
😊 Идея:
В DAG вершина с отсутствующими входящими рёбрами (in_degree = 0
) является источником. Если в графе ровно один источник, он становится кандидатом в чемпионы, так как из него достижимы все остальные вершины
(Нетривиальный момент: это утверждение не верно в общем случе, но в случае DAG его несложно доказать).
Если источников больше или ни одного, чемпиона не существует.
Сложность
-
🕒 Временная сложность:
O(m)
: Обход рёбер для подсчёта входящих рёбер.
O(n)
: Проход по массиву in_degree.
- Итого:
O(n+m)
.
-
🗂️ Пространственная сложность:
O(n)
: Для хранения массива in_degree
.
Исходный код решения
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, °ree) 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
}
}
}
ответить
Сегодня на очереди задача 2825. Make String a Subsequence Using Cyclic Increments.
Описание задачи 📝
Даны две строки str1
и str2
. Нужно определить, можно ли сделать str2
подпоследовательностью строки str1
, выполнив не более одной операции циклического увеличения произвольного набора символов в str1
.
Циклический сдвиг означает, что 'a'
становится 'b'
, 'b'
— 'c'
, ..., 'z'
— 'a'
.
Идея решения 💡
Задача почти идентична проверке подпоследовательности в строке. Единственное отличие — сравнение символов становится чуть сложнее из-за необходимости учитывать циклический сдвиг.
Мы выделяем проверку совпадения символов в отдельный метод, а в остальном используем стандартный алгоритм проверки подпоследовательности.
Реализация подхода 🚀
- Используем два итератора для последовательного прохода по символам строк.
- Для сравнения символов применяем отдельную функцию, учитывающую как прямое совпадение, так и циклический сдвиг.
- При совпадении текущего символа строки
str2
с символом из str1
, переходим к следующему символу в str2
.
- Если все символы
str2
найдены в str1
в правильном порядке, возвращаем true
, иначе — false
.
Сложность алгоритма 📊
Читать дальше →
ответить
Ответ спасен из Яндекс.Кью
Это, внезапно, одна из лучших научно-популярных книжек из тех, что я читал за последние годы. Тема, казалось бы, узкая (о некотором античном механизме, найденном в останках кораблекрушения, и попытках разгадать, для чего он служил и как был устроен), но автор настолько фантастически и разносторонне образован, и настолько системно мыслит, что за пару абзацев мимоходом меняет читателю представление о целых масштабных областях.
Чтобы не быть голословным: все мы со школы помним про "бронзовый век", да? Не знаю, как вы, а я с тех пор его так и представлял как-то очень упрощенно. Были люди в шкурах и всё такое, потом научились обработке металлов, люди с бронзовыми мечами легко выносили людей с каменными или даже с медными топорами, ну и понеслась. Так вот, как известно, бронза -- сплав меди с оловом. То ли первая, то ли одна из первых цивилизаций бронзового века, Эгейская (3200 до н.э.), выплавляла бронзу на Кипре, где были удобные для разработки месторождения меди, а олово для этого доставлялось, тадам, из Англии. Представьте себе размеры и сложность необходимых для этого торговых путей и общества в целом. Вот вам и пещерные люди.
Отличие хороших книжек от интернета, если кому-то нужно его доказывать, иллюстрируется тем фактом, что из википедии, например, понять это невозможно, даже если читать именно статью "Бронзовый век", просто не поймешь, на что смотреть.
Или вот другой факт: оказывается, императорская Япония вполне себе разрабатывала ядерное оружие и в 1945 году даже приступила к строительству установки по обогащению урана, чуть-чуть не успели, в общем. Как так получается, что я об этом впервые читаю в книжке, вообще совершенно не об этом написанной?!
Ещё очень радует, что автор, когда ему что-то непонятно, в отличие от большинства своих коллег, не стесняется так и писать: непонятно. После распространенного в научпопе сциентистского высокомерия это освежает. Почему античная цивилизация, дойдя до паровой машины и точных механических калькуляторов, вместо вступления в индустриальную эру решила погибнуть, непонятно. Имеющиеся разъяснения выглядят как средневековое "чеснок исцеляет благодаря своей исцелительной силе", исчерпывающего и убедительного объяснения нет.
На всякий случай, передам предупреждение от старших товарищей, увлекающихся историей техники: говорят, что автор местами увлекается сенсационными интерпретациями в ущерб более банальным, так что самые удивляющие фрагменты лучше перепроверять по независимым источникам. Тем не менее, книжку горячо рекомендую, давайте весь тираж срочно скупим, чтобы такое продолжали переводить и издавать.
ответить
Спасибо загадочному пользователюleetcoder, здесь опять есть какая-то жизнь. По такому случаю попробуем сюда писать в формате классического web log, вдруг получится не бросить?
Прикольная статья про силу воли и выгорание. Как всегда на lesswrong, длинновато и напоминает домашнюю философию, но основная мысль крайне простая и что-то в ней есть.
У каждого человека есть "бюджет" силы воли. Внутренний нарратор-планировщик, он же "Система 2", когда вы хотите сделать что-то неприятное, берёт кредит из этого "бюджета". Когда в вашей жизни происходит что-то приятное (приятное на базовом, бессознательном уровне), связанное с предыдущими решениями планировщика, бюджет пополняется. Если в бюджете нет средств, вы "выгорели", у вас "не хватает силы воли". Важная часть мысли состоит в том, что "приятное" определяется бессознательно, "системой 1". Например, вы очень любите мороженое; съесть мороженое и заработать $1000 могут оказаться одинаково ценными пополнениями бессознательного бюджета, хотя объективно первое примерно в тысячу раз дешевле. Это позволяет управлять "бюджетом" на сознательном уровне, решая оптимизационную задачу, и помогать другим в том же. Например, взрослые люди, как правило, недохвалены: если они делают свою работу профессионально, затратив на это немало усилий, в том числе и волевых, то это "само собой разумеется".
ответить
Наверняка у вас были книжки о математике/программированию, которыми вы зачитывались в подростковом возрасте?
Из тех, которые запомнились мне:
"Математические новеллы", Гарднера и "Алиса в стране смекалки" Рэймонда Смаллиана - обе могу порекомендовать как взрослым, так и детям. #books #math
4 ответа
Сегодня у нас еще одна задача на аккуратное манипулирование индексами 2337. Move Pieces to Obtain a String.
Описание задачи
Даны две строки start
и target
длины n
, содержащие символы 'L'
, 'R'
и '_'
.
- Символ
'L'
может двигаться только влево, если есть пустое место ('_'
) слева.
- Символ
'R'
может двигаться только вправо, если есть пустое место ('_'
) справа.
- Необходимо определить, можно ли преобразовать строку
start
в строку target
с соблюдением этих правил.
Идея 🧠
Задача сводится к тому, чтобы проверить, совпадают ли позиции и направления символов 'L'
и 'R'
в двух строках с учётом их ограничений на движение. Мы используем итерацию по строкам одновременно, отслеживая доступные символы 'L'
и 'R'
через счётчики.
Подход 🛠️
- Используем метод
as_bytes()
, чтобы быстро перебрать символы в виде байтов.
- Одновременно проходим по обеим строкам:
- Если видим
'L'
в target
, увеличиваем счётчик доступных 'L'
.
- Если видим
'L'
в start
, проверяем, есть ли доступный 'L'
, и уменьшаем счётчик.
Читать дальше →
ответить
Итак, я нагло спарсил 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 ответа
Задача на выходные - 2097. Valid Arrangement of Pairs
Описание задачи 📜
Нужно переставить заданные пары [starti,endi]
так, чтобы получилось корректное расположение,
где для каждой пары i: endi−1=starti
. Гарантируется, что такое расположение существует.
Обзор решения 🛠
Для решения задачи используется алгоритм Хирхольцера, который позволяет построить Эйлеров путь (или цикл) в ориентированном графе. Основная идея — удалять рёбра во время обхода, что упрощает структуру данных и предотвращает повторное использование рёбер.
Ключевые шаги 🚀
-
Построение графа:
- Граф представляется в виде списка смежности (
HashMap<i32, Vec<i32>>
), где каждая вершина хранит список своих исходящих рёбер.
- Параллельно вычисляются разницы степеней вершин (входящих и исходящих рёбер) для определения начальной вершины пути.
-
Поиск начальной вершины:
- Начальная вершина — это вершина с положительным балансом исходящих рёбер. Если таких нет, берётся любая вершина из входных данных.
-
Итеративный DFS с удалением рёбер:
- Вместо стандартного рекурсивного DFS используется итеративный подход с явным стеком. Это повышает эффективность памяти и скорость.
- При посещении вершины рёбра удаляются из списка смежности, что гарантирует, что каждое ребро используется ровно один раз.
Читать дальше →
ответить
Год назад, когда Карпатый присоединился к OpenAI, я удивлялся, как они умудряются нанимать таких людей на такие роли. Вроде как он у них занимался тем же, чем у нас условные миддлы занимаются. Если кто вдруг не знает, до этого он был директором по AI в Тесла, и вообще очень известный в индустрии человек со своей страничкой в Википедии, десятками тысяч звезд на Гитхабе и т.п.
Через год они себя переплюнули, уволив его как не справляющегося. В твиттере этого в явном виде не написано, но уход в никуда, отсутствие рассказов о том, что классное он успел сделать, и обще-обтекаемые фразы, что все всеми довольны и никаких претензий нет вызывают четкое узнавание ситуации.
Так вот вопрос, как они умудрились собрать команду, в которой Андрей выглядит "ниже ожиданий", и которая силами 200-300 человек регулярно унижает остальной мир, включая фаанги? У меня есть единственное предположение - они тупо платят втрое больше других, но при этом хорошо знают, кому, и потому перекупают у остальных действительно ключевых людей. Но даже это весьма непросто устроить.
7 ответов
Сегодня нам предстоит решить задачу 2577. Minimum Time to Visit a Cell In a Grid.
📝 Описание задачи
- Дана матрица
grid
размером m x n
, где каждая ячейка (row
, col
) содержит время открытия ворот, ведущих в эту ячейку. До этого времени в ячейку попасть нельзя.
- Вы начинаете в ячейке (
0
, 0
) с временем 0
и можете двигаться на 1 ячейку за секунду в любом из 4 направлений (вверх, вниз, влево, вправо).
- Важно: стоять на месте запрещено — вы должны перемещаться на каждое движение.
- Цель — найти минимальное время, чтобы добраться до ячейки (
m-1
, n-1
). Если это невозможно, вернуть -1
.
💡 Идея
Задача сводится к поиску кратчайшего пути с учётом времени открытия ворот в каждой ячейке. Можно представить задачу как динамический граф, где вершины — это пары (время, ячейка), а рёбра — это возможные переходы между ячейками. Вместо того чтобы хранить весь граф, мы динамически вычисляем возможные переходы из посещаемых вершин. Вершины будем перебирать в порядке времён достижимости ячейки (как в алгоритме Дейкстры).
🔑 Подход к решению
- 🧑💻 Графовая модель:
- Ячейки матрицы — вершины графа.
- Рёбра между вершинами имеют вес
1
.
Читать дальше →
ответить
Сегодня рассмотрим достаточно простое решение задачи 2779. Maximum Beauty of an Array After Applying Operation.
Условие 📋
Дан массив nums
и целое неотрицательное число k
. Разрешается заменить каждый элемент массива (не более одного раза) любым числом из диапазона [nums[i]−k,nums[i]+k]
. Требуется найти максимальную длину подпоследовательности массива, состоящей из одинаковых элементов (это называется "красота массива").
Идея 💡
Фактически задача сводится к нахождению наибольшего подмножества массива, все элементы которого укладываются в интервал длины 2×k
. Чтобы эффективно найти такой диапазон, можно использовать метод скользящего окна по предварительно отсортированному массиву.
Подход 🛠️
- Сортировка массива: Упорядочиваем массив, чтобы элементы, которые могут принадлежать одному диапазону, оказались рядом.
- Скользящее окно: Используем два указателя (
l
и r
) для определения максимального диапазона, удовлетворяющего условию nums[r]−nums[l]≤2×k
.
- Подсчёт длины диапазона: На каждом шаге обновляем результат как максимум текущей длины окна
r−l
.
Асимптотика 📊
- Временная сложность:
O(nlogn)
из-за сортировки + O(n)
для скользящего окна, итого O(nlogn)
.
- Пространственная сложность:
O(1)
, если используется сортировка "на месте".
Исходный код решения
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
}
}
ответить
Сегодня нам предстоит несложная задача - 2182. Construct String With Repeat Limit. Но технически она получилась муторной - требует от программиста очень аккуратного подхода к себе :)
Задача 📜
Дана строка s
, состоящая из произвольных символов, и число repeat_limit
. Необходимо построить лексикографически максимальную строку, используя символы из s
, но с ограничением:
- один и тот же символ не может встречаться более
repeat_limit
раз подряд.
Подход 🚀
-
Подсчёт частоты символов:
- Используем массив размера
256
, чтобы подсчитать количество вхождений каждого байта (символа).
-
Жадный выбор символов:
- Обходим пространство символов (
0–255
), начиная с самого большого.
- Добавляем текущий символ в результат до
repeat_limit
раз или пока его количество не исчерпается.
- Если нужно "разорвать" последовательность, вставляем следующий по величине символ, уменьшая его количество.
-
Эффективный поиск следующего символа:
- Вспомогательная функция
find_last_valid_index
ищет ближайший допустимый символ с ненулевой частотой, используя знание о текущем символе как ускоряющую подсказку.
Читать дальше →
2 ответа
Aphantasia - состояние, при котором человек, воображая что-то, не формирует при этом зрительные образы.
Многие носители афантазии описывают свои ощущение от открытия, что это, оказывается, не универсально, примерно так (цитирую по памяти):
как будто вы прочитали в википедии статью о том, что у небольшого количества людей нет чешуйчатого хвоста и это называется acaudia. Какого еще чешуйчатого хвоста? Как это "у небольшого количества"? ...А я тогда кто?
У меня у самого афантазия. Я не знал о том, что у меня нет чешуйчатого хвоста, до 30+ лет, и абзац выше очень похож на мои собственные ощущения от этого открытия.
Я примерно понимаю, что имеется в виду под "формированием зрительных образов", так как со мной иногда такое бывает, если я закрываю глаза, но не сплю, при очень сильной усталости (я даже думал, что это разновидность галлюцинаций), но в нормальном состоянии и сознательно делать это почти невозможно.
Объясню для (нормальных в этом смысле) айтишников, о чем речь. Когда я говорю "я представил себе дерево с оранжевой кроной, на котором висят качели, сделанные из старой шины", я не вижу перед собой дерево, ни в каком смысле слова "вижу"; у меня просто нет отдельной копии 2d визуального буфера под такую задачу. Вместо этого я делаю совсем другое, а именно, погружаю в оперативную память указатели на понятия "дерево", "оранжевая крона", "качели", "старая шина" и связи между ними. Это позволяет мне дальше производить, в общем, почти те же операции с тем, что я "представил", что и нормальные люди, за исключением некоторых специальных случаев вроде рисования. Думаю, именно из-за этого я могу рисовать мультяшки, пиксельарт и карикатуры, но не научился рисовать сколько-нибудь реалистично, хотя пробовал.
Читать дальше →
8 ответов
Наступление зимы отметим разбором простой задачи 1346. Check If N and Its Double Exist.
Описание задачи 🧮
Дан массив целых чисел arr
. Нужно определить, существуют ли такие индексы i
и j
, что:
- i≠j
,
- arr[i]=2⋅arr[j]
.
Обзор решения 🚀
Решение использует два простых прохода по массиву:
-
Первый проход:
- Создаем хеш-таблицу, где для каждого элемента записываем количество его удвоенных значений.
-
Второй проход:
- Проверяем, существует ли текущий элемент в хеш-таблице.
- Для нуля (
0
) дополнительно проверяем, встречается ли он в массиве как минимум дважды (так как 2⋅0=0
).
Временная сложность ⏱️
- Первый проход:
O(n)
— построение хеш-таблицы.
- Второй проход:
O(n)
— проверка условий.
- Итоговая сложность:
O(n)
.
Пространственная сложность 📦
O(n)
— память для хеш-таблицы.
Исходый код решения
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 ответ
Сегодня чуток похулиганим и предоставим переоптимизированное решение для задачи 2554. Maximum Number of Integers to Choose From a Range I. В реальном интервью такое могут потребовать лишь на уровне идеи, но нам интересно запрограммировать самим :)
Описание задачи 📋
Необходимо выбрать максимально возможное количество чисел из диапазона [1,n]
, при этом соблюдая ограничения:
- Числа из списка banned
выбирать нельзя.
- Каждое число можно использовать не более одного раза.
- Сумма выбранных чисел не должна превышать maxSum
.
Результатом должно быть количество чисел, которые можно выбрать, удовлетворяя этим условиям.
Идея решения 💡
Предвычисляем суммы запрещённых чисел и используем двоичный поиск, чтобы найти максимальное k
, для которого сумма допустимых чисел в диапазоне [1,k]
не превышает maxSum
. Это позволяет эффективно учитывать ограничения и избежать лишних вычислений.
Обзор решения 🧠
-
Сортировка и удаление дубликатов:
- Сортируем массив
banned
и удаляем повторяющиеся элементы.
-
Предвычисление кумулятивных сумм:
- Создаем массив
ban_sums
, где на позиции i
содержится сумма первых i
запрещённых чисел. Это позволяет быстро вычислять сумму запрещённых чисел до любого предела.
Читать дальше →
ответить
Сегодня мы решаем задачу 3243. Shortest Distance After Road Addition Queries I
Постановка
В задаче требуется вычислить кратчайший путь от города 0
до города n-1
после каждой из последовательных добавлений новых дорог в граф. Изначально города соединены цепочкой дорог, и после каждой операции добавляется новая односторонняя дорога между двумя городами. Необходимо после каждой операции находить кратчайшее расстояние от города 0
до города n-1
.
🔍 Идея
Данное решение использует оптимизированный подход с поочередным обновлением расстояний с помощью BFS и ранним выходом при нахождении цели (города n-1
). Мы обновляем граф и расстояния только при необходимости, что позволяет сократить количество ненужных вычислений и повысить производительность.
📚 Обзор решения
-
Инициализация графа и расстояний:
- Сначала создаем список смежности
succ
, который представляет дороги между городами, инициализируем его так, чтобы города были соединены цепочкой (каждый город соединен с следующим).
- Массив
dist
инициализируется так, что расстояние от города 0
до города i
равно i
(для начальной цепочки).
-
Обработка запросов:
- Для каждого запроса добавляется новая дорога между городами
u
и v
. После этого запускается BFS с города v
для обновления кратчайших расстояний до всех достижимых городов.
Читать дальше →
ответить
Новый день - новая задача 2109. Adding Spaces to a String.
Условие 🧩
Дана строка s
и массив индексов spaces
. Нужно добавить пробелы перед символами строки, расположенными по данным индексам, и вернуть новую строку. Например, для s = "EnjoyYourCoffee"
и spaces = [5, 9]
результатом будет "Enjoy Your Coffee"
.
Если решать абы как, то можно и в ней запутаться в индексах. Мы же будем делать все максимально просто.
Идея решения 🧠
Вместо создания промежуточных строк или модификации исходной строки, мы используем построение строки с выделением памяти заранее, чтобы минимизировать накладные расходы.
Подход 🔍
- Предварительно выделяем память для результирующей строки с помощью
String::with_capacity
, учитывая длину строки и количество пробелов.
- Проходим по массиву индексов spaces:
- Добавляем в результат подстроку от предыдущей позиции до текущего индекса.
- Добавляем пробел.
- После цикла добавляем оставшуюся часть строки.
- Возвращаем итоговую строку.
Анализ сложности 📊
- Временная сложность:
O(n)
, где n=длина строки+количество пробелов
. Все операции выполняются за один проход.
- Пространственная сложность:
O(n)
, поскольку результирующая строка создаётся с заранее выделенной памятью.
Исходный код решения
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 ответа
Сегодня разберём ещё одну простую задачу 1455. Check If a Word Occurs As a Prefix of Any Word in a Sentence.
Описание задачи 📜
Дана строка sentence, состоящая из слов, разделённых пробелами, и строка searchWord
. Нужно определить индекс (считаем с 1), где searchWord
является префиксом какого-либо слова в sentence. Если такого слова нет — вернуть -1
.
Решение 🛠️
Идея 💡
Задача сводится к простому проходу по словам строки. Мы должны проверить каждое слово: начинается ли оно с searchWord
. Возвращаем индекс первого подходящего слова.
Алгоритм 🚀
- Разделяем строку
sentence
на слова с помощью метода split_whitespace
, который возвращает ссылки на части исходной строки.
- Проходим по словам с их индексами через
enumerate
.
- Для каждого слова проверяем, начинается ли оно с
searchWord
с помощью метода starts_with
.
- Если находим соответствие, возвращаем индекс (преобразуем его в формат 1-based). Если совпадений нет, возвращаем
-1
.
Анализ Сложности 📊
-
Временная сложность:
O(n)
, где n
— длина строки sentence. Разделение строки и проверка префикса выполняются за линейное время.
-
Пространственная сложность:
O(k)
, где k
— количество слов в предложении. Дополнительная память используется только для хранения указателей на слова, а не самих слов.
Исходный код решения
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 ответа
В "остальное" вошли США, Германия, Израиль и почему-то Китай. Какие выводы можно сделать, кроме "нотка стронк", я не знаю, просто хотел показать )
4 ответа
Сегодня нам предстоит решить задачу 1792. Maximum Average Pass Ratio.
Описание задачи 📚
У нас есть школа, где классы проводят итоговые экзамены. Каждый класс описывается массивом [pass_i,total_i]
, где:
pass_i
— количество учеников,
Читать дальше →
2 ответа
На нашей новой задаче 2415. Reverse Odd Levels of Binary Tree есть повод продемонстировать продвинутые методы Rust работы с итераторами (std::iter::successors
& std::iter::zip
), а также "непристойную" работу c реф-каунт ячейками :(
📜 Описание задачи
Дано идеальное бинарное дерево. Требуется изменить порядок значений узлов на всех нечетных уровнях дерева.
Идеальное дерево — это дерево, где у каждого узла два потомка, а все листья находятся на одном уровне.
💡 Идея
Мы адаптируем BFS для обхода дерева по уровням. На каждом уровне проверяется, нужно ли инвертировать порядок значений (для нечетных уровней). С помощью вспомогательной функции формируются следующие уровни дерева.
📋 Подробности подхода
-
Вспомогательная функция
next_level
:
- Формирует следующий уровень дерева, собирая всех левых и правых потомков текущих узлов.
-
Завершение обработки:
- Проверка, что текущий уровень является листовым, выполняется через условие
nodes[0].borrow().left.is_none()
.
- При достижении уровня листьев обработка завершается.
-
Обход уровней с помощью
std::iter::successors
:
- Используется функциональный подход для последовательного формирования уровней дерева. Итератор автоматически останавливается при достижении листового уровня.
Читать дальше →
ответить
Очередная задача: 2290. Minimum Obstacle Removal to Reach Corner.
📄 Описание задачи
Дана двумерная матрица grid
размером m x n
, где каждая клетка может быть либо пустой (0
), либо препятствием (1
), которое можно удалить. Задача заключается в том, чтобы найти минимальное количество препятствий, которые нужно удалить, чтобы пройти из верхнего левого угла (0, 0)
в нижний правый угол (m-1, n-1)
, передвигаясь только по пустым клеткам или удаляя препятствия.
🔑 Идея
Для решения задачи используем модификацию алгоритма поиска в ширину (BFS), который эффективно обрабатывает препятствия. Вместо приоритизации клеток по расстоянию, как в стандартном алгоритме Дейкстры, в 0-1 BFS (именно так эту модификацию принято называть) мы обрабатываем сначала пустые клетки, а затем клетки с препятствиями, что позволяет нам минимизировать количество удаляемых препятствий.
📋 Подробное описание подхода
-
Инициализация: Мы создаем две очереди:
front
и back
. Во front
помещаем клетки, которые можно пройти без удаления препятствий, а в back
— клетки, для которых потребуется удалить препятствие.
-
Поиск в ширину (BFS):
- Начинаем с верхнего левого угла и устанавливаем расстояние для этой клетки в
0
(т.е. препятствий еще не удалено).
- Если клетка пустая (значение
0
), мы добавляем её в front
. Если клетка — препятствие (значение 1
), то в back
.
Читать дальше →
ответить
Сегодня решаем задачу 2054. Two Best Non-Overlapping Events. Будем закреплять двоичный поиск ;)
😇 Описание задачи
Дан список событий с известными для них start_time
, end_time
и value
. Нужно выбрать максимум два непересекающихся события с максимальной общей ценностью. События пересекаются, если одно начинается до окончания другого.
💡 Идея
Сортируем события по end_time
(в убывающем порядке). Для каждого события используем двоичный поиск, чтобы найти все заканчивающиеся до его начала. Остаётся найти среди них событие с максимальной ценностью, для этого будем хранить накопленные максимальные ценности в отдельном массиве max_vals
.
🛠️ Подход
-
Сортировка событий: По
end_time
в порядке убывания.
-
Предобработка максимальных ценностей: Создаём массив
max_vals
с накопленной максимальной ценностью событий (справа-налево).
-
Итерация и поиск:
- Для каждого события находим первое, заканчивающееся раньше его, через двоичный поиск.
- Суммируем ценности текущего события и накопленной максимальной ценности по найденному индексу, обновляя общий максимум.
Читать дальше →
ответить
Сегодняшняя задача 1475. Final Prices With a Special Discount in a Shop решается с помощью стандартного стека, но интересно и нестандартно выглядит мотивация его использования.
Описание задачи 🛒
У вас есть массив цен prices
, где prices[i]
— это цена i
-го товара. Если вы покупаете товар i
, вы можете получить скидку, равную цене первого товара с индексом j>i
, для которого выполняется условие prices[j] ≤ prices[i]
. Если такого товара нет, скидка не применяется. Требуется вернуть массив, где каждая позиция показывает финальную цену с учётом скидки.
Идея 🤔
- Мы идём по массиву цен и обрабатываем товары по порядку.
- Для каждого товара находим, для каких товаров он определяет скидку, проверяя необработанные товары с индексами слева, чья цена больше или равна текущей.
- Чтобы эффективно отслеживать эти необработанные товары, используем монотонный стек. Этот стек хранит индексы товаров, цены которых упорядочены по возрастанию. Это позволяет быстро находить и применять скидки.
Подход 🚀
- Создаём стек
discount_candidates
, чтобы хранить индексы товаров, ожидающих применения скидки.
- Итерируем по массиву
prices
:
- Пока верхний элемент стека соответствует условию скидки (
цена товара в стеке ≥ текущей цене
), применяем скидку и удаляем элемент из стека.
Читать дальше →
ответить
Страница
1
2
3
4