Рынок пока жив, и мы это видим
Последнее время вокруг IT много разговоров, что рынок сдулся, вакансий нет, компании фризят найм.
Несмотря на всю ситуации, наших студентов приглашают на интервью, и они собирают офферы💰
Кто-то пришёл на СТАРТ летом, кто-то подключился к ПРО в сентябре. И сейчас мы уже видим результаты!
Почему у них получается? Потому что после курсов ребята выходят на рынок осознанно и готовыми ко всему пути до оффера. Этим и выигрывают на фоне тех, кто бездумно откликается, валит собесы и винит во всем рынок.
Как вас ведем до оффера:
➡️ Сначала закрываем техническую часть: теория, много практики, ДЗ и пет-проекты с проверкой, реальные задачи и вопросы с собеседований, подготовка к техническим секциям
➡️ Далее преподаватели помогают собрать карьерную стратегию: понять, куда подаваться, как упаковать опыт, оформить резюме и LinkedIn, писать сопроводительные и выстроить стратегию откликов так, чтобы повышать шанс попасть на собеседование
➡️ Отрабатываем на практике: mock-собеседования, где в условиях, приближенным к реальному собеседованию, вы проходите техническую секцию и мотивационную
К моменту выхода на рынок у вас уже собрана вся подготовка:
харды + проекты + резюме + упакованный опыт + стратегия откликов + навык проходить собеседования
Лучшим студентам мы помогаем с рефералками и рекомендуем их в компании.
А если вы прошли курсы, выполнили рекомендации, но оффер не получили — вернём деньги.
⭐ ЗАПИСАТЬСЯ НА КУРС⭐️
Последнее время вокруг IT много разговоров, что рынок сдулся, вакансий нет, компании фризят найм.
Несмотря на всю ситуации, наших студентов приглашают на интервью, и они собирают офферы
Кто-то пришёл на СТАРТ летом, кто-то подключился к ПРО в сентябре. И сейчас мы уже видим результаты!
Почему у них получается? Потому что после курсов ребята выходят на рынок осознанно и готовыми ко всему пути до оффера. Этим и выигрывают на фоне тех, кто бездумно откликается, валит собесы и винит во всем рынок.
Как вас ведем до оффера:
К моменту выхода на рынок у вас уже собрана вся подготовка:
харды + проекты + резюме + упакованный опыт + стратегия откликов + навык проходить собеседования
Лучшим студентам мы помогаем с рефералками и рекомендуем их в компании.
А если вы прошли курсы, выполнили рекомендации, но оффер не получили — вернём деньги.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Дождались! Ребята сделали крутейший канал про IT новой эпохи
Нейросети, ИИ-агенты, вайбкодинг, вайбхакинг и новые инструменты уже меняют привычный мир технологий.
Там разбирают эти изменения и другие интересные IT-темы на простых картинках и понятном языке, а еще делятся полезными ресурсами и свежими новостями
Подписывайтесь: @IT_Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1🗿1
Задача с собеседования в OYO
Дан целочисленный массив nums. Верните все тройки [nums[i], nums[j], nums[k]] такие, что i != j, i != k и j != k, а также nums[i] + nums[j] + nums[k] == 0.
Обратите внимание, что результирующий набор не должен содержать дублирующиеся тройки.
Пример 1:
Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Explanation:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.
Искомые тройки: [-1,0,1] и [-1,-1,2].
Обратите внимание, что порядок вывода и порядок троек не имеют значения.
Пример 2:
Input: nums = [0,1,1]
Output: []
Explanation: Сумма единственной возможной тройки не равна 0.
Пример 3:
Input: nums = [0,0,0]
Output: [[0,0,0]]
Explanation: Единственная возможная тройка даёт в сумме 0.
Ограничения:
3 <= nums.length <= 3000
-10⁵ <= nums[i] <= 10⁵
НАШ ЧАТ АЛГОРИТМИСТОВ
Решение
Для оптимального решения используем предварительную сортировку и метод двух указателей, движущихся навстречу друг другу.
После сортировки сумма будет монотонно зависеть от положения указателей: если сдвигаем l вправо - сумма не уменьшается (растёт или остаётся прежней из-за дубликатов), если сдвигаем r влево - сумма не увеличивается (уменьшается или остаётся прежней из-за дубликатов). Сортировка также упрощает обработку дубликатов, которые теперь стоят рядом.
Фиксируем первое число тройки как nums[i] и проходим переменной i по массиву nums.
Если nums[i] > 0: прерываем цикл, так как оставшиеся числа точно положительные.
Если i > 0 и nums[i] == nums[i - 1]: пропускаем текущую итерацию, так как встретили дубликат первого числа в тройке.
Инициализируем указатели:
l - указывает на эл-т, следующий за текущим i
r - указывает на последний эл-т массива
Пока l меньше r, двигаем указатели навстречу друг другу:
Вычисляем общую сумму тройки эл-в.
Если сумма больше 0:
- уменьшаем r.
Если сумма меньше 0:
- увеличиваем l.
Если сумма равна 0:
- добавляем эту тройку в res;
- сдвигаем l вправо и пропускаем дубликаты nums[l], если они есть, сдвигая l ещё раз вправо.
Возвращаем res, содержащий все уникальные тройки, сумма которых равна 0.
Сложность
O(n^2) - по времени (сортировка - O(n log n); внешний цикл - O(n), на каждой итерации i - проход двумя указателями в цикле while за O(n). Итого: O(n^2))
O(1) - по памяти (храним некоторое кол-во переменных; без учёта сортировки)
Код
class Solution:
def threeSum(self, nums: list[int]) -> list[list[int]]:
nums.sort()
res = []
for i in range(len(nums)):
if nums[i] > 0:
break
if i > 0 and nums[i] == nums[i - 1]:
continue
l, r = i + 1, len(nums) - 1
while l < r:
three_sum = nums[i] + nums[l] + nums[r]
if three_sum > 0:
r -= 1
elif three_sum < 0:
l += 1
else:
res.append([nums[i], nums[l], nums[r]])
l += 1
while l < r and nums[l] == nums[l - 1]:
l += 1
return res
@algoses
Дан целочисленный массив nums. Верните все тройки [nums[i], nums[j], nums[k]] такие, что i != j, i != k и j != k, а также nums[i] + nums[j] + nums[k] == 0.
Обратите внимание, что результирующий набор не должен содержать дублирующиеся тройки.
Пример 1:
Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Explanation:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.
Искомые тройки: [-1,0,1] и [-1,-1,2].
Обратите внимание, что порядок вывода и порядок троек не имеют значения.
Пример 2:
Input: nums = [0,1,1]
Output: []
Explanation: Сумма единственной возможной тройки не равна 0.
Пример 3:
Input: nums = [0,0,0]
Output: [[0,0,0]]
Explanation: Единственная возможная тройка даёт в сумме 0.
Ограничения:
3 <= nums.length <= 3000
-10⁵ <= nums[i] <= 10⁵
НАШ ЧАТ АЛГОРИТМИСТОВ
Решение
После сортировки сумма будет монотонно зависеть от положения указателей: если сдвигаем l вправо - сумма не уменьшается (растёт или остаётся прежней из-за дубликатов), если сдвигаем r влево - сумма не увеличивается (уменьшается или остаётся прежней из-за дубликатов). Сортировка также упрощает обработку дубликатов, которые теперь стоят рядом.
Фиксируем первое число тройки как nums[i] и проходим переменной i по массиву nums.
Если nums[i] > 0: прерываем цикл, так как оставшиеся числа точно положительные.
Если i > 0 и nums[i] == nums[i - 1]: пропускаем текущую итерацию, так как встретили дубликат первого числа в тройке.
Инициализируем указатели:
l - указывает на эл-т, следующий за текущим i
r - указывает на последний эл-т массива
Пока l меньше r, двигаем указатели навстречу друг другу:
Вычисляем общую сумму тройки эл-в.
Если сумма больше 0:
- уменьшаем r.
Если сумма меньше 0:
- увеличиваем l.
Если сумма равна 0:
- добавляем эту тройку в res;
- сдвигаем l вправо и пропускаем дубликаты nums[l], если они есть, сдвигая l ещё раз вправо.
Возвращаем res, содержащий все уникальные тройки, сумма которых равна 0.
Сложность
O(1) - по памяти (храним некоторое кол-во переменных; без учёта сортировки)
Код
def threeSum(self, nums: list[int]) -> list[list[int]]:
nums.sort()
res = []
for i in range(len(nums)):
if nums[i] > 0:
break
if i > 0 and nums[i] == nums[i - 1]:
continue
l, r = i + 1, len(nums) - 1
while l < r:
three_sum = nums[i] + nums[l] + nums[r]
if three_sum > 0:
r -= 1
elif three_sum < 0:
l += 1
else:
res.append([nums[i], nums[l], nums[r]])
l += 1
while l < r and nums[l] == nums[l - 1]:
l += 1
return res
@algoses
❤2
Стажировка в BigTech или ШАД? Будь готов, что спросят про LLM.
На собесах в ML всё чаще говорят про агентов, RAG и свежие модели. Пока ты решаешь матан, индустрия уже ушла туда.
Каждый день разбираем коротко, с кодом и ссылками на статьи. Чтобы на собесе было что рассказать.
🎁 А для своих собрали папку для подготовки-: матан, бесплатные книги по ИИ и стажировки.
Читай до собеса, а не после: t.me/data_analysis_ml
На собесах в ML всё чаще говорят про агентов, RAG и свежие модели. Пока ты решаешь матан, индустрия уже ушла туда.
Каждый день разбираем коротко, с кодом и ссылками на статьи. Чтобы на собесе было что рассказать.
🎁 А для своих собрали папку для подготовки-: матан, бесплатные книги по ИИ и стажировки.
Читай до собеса, а не после: t.me/data_analysis_ml
❤3👍2🔥2
Что делать с данными? 💬
Строить отчёты. А ещё, например:
В Школе аналитиков данных МТС учатся решать такие задачи на практике.
В программе — SQL и Python, математика и статистика, анализ данных, машинное обучение и большие данные, а также нейросети и рекомендательные системы.
Занятия ведут действующие эксперты Центра BigData MWS. Теория чередуется с практикой, а преподаватели дают обратную связь по работам и помогают отслеживать прогресс.
Это будет интересно:
Обучение продлится 10 месяцев и будет полностью бесплатным.
⚡️ Сейчас — последний шанс подать заявку, так как прием закрывается 25 октября. Для поступления кандидатам предстоит заполнить анкету, написать мотивационное письмо и пройти отборочное тестирование.
Отправить заявку↗️
Строить отчёты. А ещё, например:
✅ находить закономерности в больших массивах;⬜️ предсказывать поведение пользователей;⬜️ строить рекомендательные системы;⬜️ обучать и улучшать ML-модели;⬜️ создавать продукты и помогать бизнесу расти.
В Школе аналитиков данных МТС учатся решать такие задачи на практике.
В программе — SQL и Python, математика и статистика, анализ данных, машинное обучение и большие данные, а также нейросети и рекомендательные системы.
Занятия ведут действующие эксперты Центра BigData MWS. Теория чередуется с практикой, а преподаватели дают обратную связь по работам и помогают отслеживать прогресс.
Это будет интересно:
➡️ студентам последних курсов и выпускникам технических вузов➡️ алитикам данных, которые хотят погружаться в исследования➡️ ИТ-специалистам, которые хотят перейти в новое для себя направление
Обучение продлится 10 месяцев и будет полностью бесплатным.
⚡️ Сейчас — последний шанс подать заявку, так как прием закрывается 25 октября. Для поступления кандидатам предстоит заполнить анкету, написать мотивационное письмо и пройти отборочное тестирование.
Отправить заявку
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍1
Задача с собеседования в eBay
Дана строка s, проверьте, можно ли составить её, взяв какую-либо её подстроку и повторив её два или более раз подряд.
Пример 1:
Input: s = "abab"
Output: true
Explanation: Это подстрока "ab", повторяющаяся дважды.
Пример 2:
Input: s = "aba"
Output: false
Пример 3:
Input: s = "abcabcabcabc"
Output: true
Explanation: Это подстрока "abc", повторяющаяся четыре раза, или подстрока "abcabc", повторяющаяся дважды.
Ограничения:
1 <= s.length <= 10⁴
s состоит из строчных английских букв.
НАШ ЧАТ АЛГОРИТМИСТОВ
Решение
Если s состоит из повторяющихся подстрок, то у неё есть длинный собственный префикс, равный её суффиксу.
Классический метод решения задачи - префикс-функция из алгоритма Кнута-Морриса-Пратта.
Префикс-функция даёт длины наибольших бордеров для всех префиксов.
Бордер - собственный префикс строки, являющийся одновременно её суффиксом. Необходимо проверить, образует ли бордер период всей строки.
Создаем массив lps (longest prefix-suffix), где lps[i] хранит длину наибольшего собственного префикса подстроки s[0..i], который одновременно является её суффиксом.
Если при вычислении префикс-функции символы не совпадают, длина префикса (k) не сбрасывается в ноль, а "откатывается" к уже вычисленному значению для более короткого префикса.
Идём по строке слева направо, храня k - длину текущего совпавшего префикса:
Пока k > 0 (префикс непустой) и s[i] != s[k] (символы не совпали):
- "откатываемся" к наибольшему валидному бордеру меньшей длины: k = lps[k - 1] (если префикс s[0..k-1] равен суффиксу s[i-k..i-1], то любой бордер строки s[0..k-1] также является бордером и для s[0..i-1]. Наибольший такой бордер имеет длину lps[k - 1]).
Если s[i] == s[k]:
- продлеваем совпавший префикс текущим символом (k += 1).
Записываем результат: lps[i] = k.
Разберем на примере 1, где s = "abab":
- Подстрока "a" (i = 0): собственных префиксов нет => lps[0] = 0.
- Подстрока "ab" (i = 1): префикс "a" != суффикс "b" => lps[1] = 0.
- Подстрока "aba" (i = 2): префикс "a" == суффикс "a" => lps[2] = 1.
- Подстрока "abab" (i = 3): префикс "ab" == суффикс "ab" => lps[3] = 2.
Получившийся массив lps: [0, 0, 1, 2]
L (длина бордера всей строки) = lps[n - 1]. Если L > 0, то префикс длины L совпадает с суффиксом длины L: s[0..L-1] == s[n-L..n-1].
Суффикс начинается с индекса n - L, т.е. для любого индекса j от 0 до L-1 будет выполняться s[j] == s[j + (n - L)]. Таким образом, строка сдвигается сама на себя с шагом p = n - L.
p - кандидат на длину минимального периода.
Чтобы строка состояла из точных повторов этого периода, должны выполняться следующие два условия:
- L > 0 (иначе p = n и n % n == 0 даст true для любой строки, к примеру, "abcd")
- n % p == 0 (общая длина строки должна нацело делиться на длину периода. К примеру, для "ababa", где n = 5, L = 3, p = 2 и 5 % 2 != 0).
Сложность
O(n) - по времени (k увеличивается не более чем на 1 за каждую итерацию внешнего цикла for, в цикле while - k только уменьшается. Таким образом, суммарное число итераций while не превышает n)
O(n) - по памяти (строим массив lps)
Код
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
n = len(s)
lps = [0] * n
for i in range(1, n):
k = lps[i - 1]
while k > 0 and s[i] != s[k]:
k = lps[k - 1]
if s[i] == s[k]:
k += 1
lps[i] = k
L = lps[n - 1]
p = n - L
return L > 0 and n % p == 0
@algoses
Дана строка s, проверьте, можно ли составить её, взяв какую-либо её подстроку и повторив её два или более раз подряд.
Пример 1:
Input: s = "abab"
Output: true
Explanation: Это подстрока "ab", повторяющаяся дважды.
Пример 2:
Input: s = "aba"
Output: false
Пример 3:
Input: s = "abcabcabcabc"
Output: true
Explanation: Это подстрока "abc", повторяющаяся четыре раза, или подстрока "abcabc", повторяющаяся дважды.
Ограничения:
1 <= s.length <= 10⁴
s состоит из строчных английских букв.
НАШ ЧАТ АЛГОРИТМИСТОВ
Решение
Классический метод решения задачи - префикс-функция из алгоритма Кнута-Морриса-Пратта.
Префикс-функция даёт длины наибольших бордеров для всех префиксов.
Бордер - собственный префикс строки, являющийся одновременно её суффиксом. Необходимо проверить, образует ли бордер период всей строки.
Создаем массив lps (longest prefix-suffix), где lps[i] хранит длину наибольшего собственного префикса подстроки s[0..i], который одновременно является её суффиксом.
Если при вычислении префикс-функции символы не совпадают, длина префикса (k) не сбрасывается в ноль, а "откатывается" к уже вычисленному значению для более короткого префикса.
Идём по строке слева направо, храня k - длину текущего совпавшего префикса:
Пока k > 0 (префикс непустой) и s[i] != s[k] (символы не совпали):
- "откатываемся" к наибольшему валидному бордеру меньшей длины: k = lps[k - 1] (если префикс s[0..k-1] равен суффиксу s[i-k..i-1], то любой бордер строки s[0..k-1] также является бордером и для s[0..i-1]. Наибольший такой бордер имеет длину lps[k - 1]).
Если s[i] == s[k]:
- продлеваем совпавший префикс текущим символом (k += 1).
Записываем результат: lps[i] = k.
Разберем на примере 1, где s = "abab":
- Подстрока "a" (i = 0): собственных префиксов нет => lps[0] = 0.
- Подстрока "ab" (i = 1): префикс "a" != суффикс "b" => lps[1] = 0.
- Подстрока "aba" (i = 2): префикс "a" == суффикс "a" => lps[2] = 1.
- Подстрока "abab" (i = 3): префикс "ab" == суффикс "ab" => lps[3] = 2.
Получившийся массив lps: [0, 0, 1, 2]
L (длина бордера всей строки) = lps[n - 1]. Если L > 0, то префикс длины L совпадает с суффиксом длины L: s[0..L-1] == s[n-L..n-1].
Суффикс начинается с индекса n - L, т.е. для любого индекса j от 0 до L-1 будет выполняться s[j] == s[j + (n - L)]. Таким образом, строка сдвигается сама на себя с шагом p = n - L.
p - кандидат на длину минимального периода.
Чтобы строка состояла из точных повторов этого периода, должны выполняться следующие два условия:
- L > 0 (иначе p = n и n % n == 0 даст true для любой строки, к примеру, "abcd")
- n % p == 0 (общая длина строки должна нацело делиться на длину периода. К примеру, для "ababa", где n = 5, L = 3, p = 2 и 5 % 2 != 0).
Сложность
O(n) - по памяти (строим массив lps)
Код
def repeatedSubstringPattern(self, s: str) -> bool:
n = len(s)
lps = [0] * n
for i in range(1, n):
k = lps[i - 1]
while k > 0 and s[i] != s[k]:
k = lps[k - 1]
if s[i] == s[k]:
k += 1
lps[i] = k
L = lps[n - 1]
p = n - L
return L > 0 and n % p == 0
@algoses
❤4