Python | LeetCode
10.1K subscribers
151 photos
1.03K links
Cайт easyoffer.ru
Реклама @easyoffer_adv
ВП @easyoffer_vp

Тесты t.me/+20tRfhrwPpM4NDQy
Вопросы собесов t.me/+cnJC0_ZeZ_I0OGY6
Вакансии t.me/+cXGKkrOY2-w3ZTky
Download Telegram
Forwarded from easyoffer
🎉 Easyoffer 2.0 — самый успешный краудфандинг в истории рунета в категории "Технологии"!

Мы это сделали! За считанные часы после старта, благодаря вашей поддержке, проект не просто стартовал — он взлетел.

💸 Собрано: 2 276 840 рублей

Это не просто цифра — это ваше доверие, ваша вера в идею, и ваша инвестиция в будущее карьеры сотен (а скоро — тысяч) специалистов.

💼 Благодаря этой сумме мы уже:

— Наняли ещё пару разработчиков и аналитиков
— Запустили активный сбор и разметку новых данных
— Ускорили разработку и подняли планку качества

Спасибо каждому, кто поверил в нас на старте! Дальше — только масштабирование и развитие. Мы строим сервис, который станет must-have для всех, кто ищет работу в IT.

👉 Присоединяйтесь сейчас — это только начало.
🔥2👍1
Задача: 657. Robot Return to Origin
Сложность: easy

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

Вам дана строка moves, представляющая последовательность движений робота, где moves[i] представляет его i-ое движение. Допустимые движения: 'R' (вправо), 'L' (влево), 'U' (вверх) и 'D' (вниз).

Верните true, если робот возвращается в исходную точку после завершения всех своих движений, или false в противном случае.

Примечание: направление, в котором "смотрит" робот, не имеет значения. 'R' всегда будет перемещать робота на один шаг вправо, 'L' всегда будет перемещать его на один шаг влево и т.д. Также предполагается, что величина перемещения робота одинакова для каждого хода.

Пример:
Input: moves = "UD"
Output: true


👨‍💻 Алгоритм:

1⃣Инициализация координат:
Начните с координат (0, 0).

2⃣Обработка движений:
Пройдите по строке moves и обновляйте координаты в зависимости от движения:
'R' увеличивает координату x на 1.
'L' уменьшает координату x на 1.
'U' увеличивает координату y на 1.
'D' уменьшает координату y на 1.

3⃣Проверка конечных координат:
Если после всех движений координаты снова равны (0, 0), верните true. В противном случае, верните false.

😎 Решение:
class Solution:
def judgeCircle(self, moves: str) -> bool:
x, y = 0, 0
for move in moves:
if move == 'R':
x += 1
elif move == 'L':
x -= 1
elif move == 'U':
y += 1
elif move == 'D':
y -= 1
return x == 0 and y == 0


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1💊1
Задача: 1258. Synonymous Sentences
Сложность: medium

Вам дан список эквивалентных пар строк synonyms, где synonyms[i] = [si, ti] означает, что si и ti являются эквивалентными строками. Вам также дан текст предложения. Верните все возможные синонимичные предложения, отсортированные лексикографически.

Пример:
Input: synonyms = [["happy","joy"],["sad","sorrow"],["joy","cheerful"]], text = "I am happy today but was sad yesterday"
Output: ["I am cheerful today but was sad yesterday","I am cheerful today but was sorrow yesterday","I am happy today but was sad yesterday","I am happy today but was sorrow yesterday","I am joy today but was sad yesterday","I am joy today but was sorrow yesterday"]


👨‍💻 Алгоритм:

1⃣Построить граф синонимов, используя структуру данных, такую как Union-Find или просто с использованием DFS/BFS.

2⃣Пройти по каждому слову в предложении и найти все возможные синонимы.
Сгенерировать все возможные комбинации предложений.

3⃣Отсортировать полученные предложения лексикографически.

😎 Решение:
from collections import defaultdict
from itertools import product

def generateSentences(synonyms, text):
graph = defaultdict(set)
for s1, s2 in synonyms:
graph[s1].add(s2)
graph[s2].add(s1)

def find_synonyms(word):
synonyms = set()
stack = [word]
while stack:
w = stack.pop()
if w not in synonyms:
synonyms.add(w)
stack.extend(graph[w])
return synonyms

words = text.split()

synonym_groups = [sorted(find_synonyms(word)) for word in words]

sentences = list(map(' '.join, product(*synonym_groups)))

sentences.sort()

return sentences


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Задача: 1354. Construct Target Array With Multiple Sums
Сложность: hard

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

Пусть x будет суммой всех элементов, находящихся в вашем массиве.
Выберите индекс i так, чтобы 0 <= i < n, и установите значение arr в индексе i равным x.
Вы можете повторять эту процедуру столько раз, сколько потребуется.
Верните true, если возможно построить массив target из arr, в противном случае верните false.

Пример:
Input: target = [8,5]
Output: true


👨‍💻 Алгоритм:

1⃣Использование максимальной кучи (Max Heap) для отслеживания максимальных значений в target:
Сначала необходимо инициализировать кучу с максимальным приоритетом, чтобы всегда иметь доступ к наибольшему элементу в массиве target.
Вычислить сумму всех элементов в target и сохранить ее.

2⃣Повторение процесса переворота:
Извлечь наибольшее значение из кучи. Вычесть это значение из общей суммы.
Проверить несколько условий:
Если извлеченное значение равно 1 или общая сумма равна 1, вернуть true.
Если извлеченное значение меньше общей суммы, общая сумма равна 0, или извлеченное значение делится на общую сумму без остатка, вернуть false.
Остаток от деления наибольшего значения на общую сумму является новым значением, которое нужно вставить обратно в кучу. Обновить общую сумму.

3⃣Повторение цикла до достижения результата:
Повторять шаг 2 до тех пор, пока не будут выполнены условия выхода из цикла (возврат true или false).

😎 Решение:
import heapq

class Solution:
def isPossible(self, target: List[int]) -> bool:
total = sum(target)
target = [-x for x in target]
heapq.heapify(target)

while -target[0] > 1:
maxVal = -heapq.heappop(target)
total -= maxVal
if maxVal < total or total == 0 or maxVal % total == 0:
return False
maxVal %= total
total += maxVal
heapq.heappush(target, -maxVal)
return True


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Forwarded from easyoffer
Что такое PRO-подписка на easyoffer 2.0?

easyoffer PRO — это не просто доступ к базе, а полноценный инструмент для получения оффера.

🧠 База вопросов с собеседований

+ Анализ на основе 4,000 собеседований
+ Вероятность встречи каждого вопроса
+ Фильтрация по грейдам, компаниям, типам интервью
+ Примеры ответов: текстовые и видео
+ Готовьтесь к собеседованию в конкретную компанию

🛠 Тренажер "Проработка вопросов"

+ Флеш-карточки + интервальные повторения
+ Персональная система показа карточек в зависимости от ваших ответов
+ Упор на наиболее частые вопросы
+ Фокус на слабые места и быстрый прогресс

🎭 Тренажер "Реальное собеседование"

+ Сценарии на основе реальных интервью
+ Подготовка к конкретным компаниям
+ Итоговая статистика: прошёл/не прошёл

🧩 База задач с собеседований

+ Live-coding и System Design задачи
+ Оценка вероятности встречи задачи
+ Подготовка к задачам по конкретным компаниям

📋 База тестовых заданий

+ Задания из реальных вакансий
+ Фильтрация по технологиям и грейдам
+ Лучшие решения в доступе

📈 Тренды технологий в вакансиях

+ Топ-100 навыков, которые требуют компании
+ Динамика популярности технологий
+ Фильтрация по грейдам

🎁 Специальная цена до релиза:
3200 руб. за целый год

Сейчас PRO на 1 год стоит как будет стоить 1 месяц после релиза. Покупка также открывает доступ к закрытому бета-тестированию.
+ Вы можете активировать подписку в любой момент, например, когда начнете искать работу.

Предзаказ здесь: https://planeta.ru/campaigns/easyoffer

📌 Цена поднимется сразу после запуска.

Если вы хотите перестать угадывать, что спросят на собеседовании, и начать точечно готовиться на основе реальных данных — easyoffer PRO именно для вас.

Экономьте время. Получайте оффер легко.
🔥1
Задача: 116. Populating Next Right Pointers in Each Node
Сложность: medium

Вам дано идеальное бинарное дерево, где все листья находятся на одном уровне, и у каждого родителя есть два детей. Бинарное дерево имеет следующее определение:

struct Node {
int val;
Node *left;
Node *right;
Node *next;
}


Заполните каждый указатель next так, чтобы он указывал на следующий правый узел. Если следующего правого узла нет, указатель next должен быть установлен в NULL.

Изначально все указатели next установлены в NULL.

Пример:
Input: root = [1,2,3,4,5,6,7]
Output: [1,#,2,3,#,4,5,6,7,#]
Explanation: Given the above perfect binary tree (Figure A), your function should populate each next pointer to point to its next right node, just like in Figure B. The serialized output is in level order as connected by the next pointers, with '#' signifying the end of each level.


👨‍💻 Алгоритм:

1️⃣Инициализируйте очередь Q, которую мы будем использовать во время обхода. Существует несколько способов реализации обхода в ширину, особенно когда речь идет о определении уровня конкретного узла. Можно добавлять в очередь пару (узел, уровень), и каждый раз, когда добавляются дети узла, мы добавляем (node.left, parent_level + 1) и (node.right, parent_level + 1). Этот подход не будет очень эффективен для нашего алгоритма, так как нам нужны все узлы на одном уровне, и для этого потребуется еще одна структура данных.

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

3️⃣Подход, который мы будем использовать здесь, будет иметь структуру вложенных циклов, чтобы обойти необходимость указателя NULL. По сути, на каждом шаге мы записываем размер очереди, который всегда соответствует всем узлам на определенном уровне. Как только мы узнаем этот размер, мы обрабатываем только это количество элементов и не более. К моменту, когда мы закончим обработку заданного количества элементов, в очереди будут все узлы следующего уровня. Вот псевдокод для этого:

while (!Q.empty())
{
size = Q.size()
for i in range 0..size
{
node = Q.pop()
Q.push(node.left)
Q.push(node.right)
}
}


Мы начинаем с добавления корня дерева в очередь. Поскольку на уровне 0 есть только один узел, нам не нужно устанавливать какие-либо соединения, и мы можем перейти к циклу while.

😎 Решение:
import collections

class Solution:
def connect(self, root: "Node") -> "Node":
if not root:
return root

Q = collections.deque([root])

while Q:
size = len(Q)
for i in range(size):
node = Q.popleft()
if i < size - 1:
node.next = Q[0]
if node.left:
Q.append(node.left)
if node.right:
Q.append(node.right)

return root


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Задача: 228. Summary Ranges
Сложность: easy

Вам дан отсортированный массив уникальных целых чисел nums.

Диапазон [a,b] - это множество всех целых чисел от a до b (включительно).

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

Каждый диапазон [a,b] в списке должен быть представлен в формате:

"a->b" если a != b
"a" если a == b

Пример:
Input: nums = [0,1,2,4,5,7]
Output: ["0->2","4->5","7"]
Explanation: The ranges are:
[0,2] --> "0->2"
[4,5] --> "4->5"
[7,7] --> "7"


👨‍💻 Алгоритм:

1⃣Создайте список строк ranges, который будет содержать решение задачи, и начните итерацию по всем элементам nums с указателем i = 0. Каждая итерация внешнего цикла представляет собой поиск одного диапазона. Для начала сохраните начало текущего диапазона в start = nums[i].

2⃣Проверьте, отличается ли следующий элемент в nums на индексе i + 1 от nums[i] на 1 или больше. Если следующий элемент отличается на 1, увеличьте i на 1, чтобы включить (i+1)-й элемент в этот диапазон и продолжайте проверку следующего элемента. Продолжайте добавлять элементы в этот диапазон, пока последовательные элементы отличаются на 1, используя цикл while для выполнения этой логики.

3⃣Если следующий элемент отличается более чем на 1 или если все элементы в nums уже обработаны, проверьте, равен ли start значению nums[i]. Если start == nums[i], добавьте только start как строку в ranges, так как у нас есть только один элемент в этом диапазоне. Если start != nums[i], добавьте строку start->nums[i] в ranges. Увеличьте i на 1, чтобы начать новый диапазон.

😎 Решение:
class Solution:
def summaryRanges(self, nums: List[int]) -> List[str]:
ranges = []
i = 0
while i < len(nums):
start = nums[i]
while i + 1 < len(nums) and nums[i] + 1 == nums[i + 1]:
i += 1
if start != nums[i]:
ranges.append(f"{start}->{nums[i]}")
else:
ranges.append(f"{start}")
i += 1
return ranges


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Задача: 350. Intersection of Two Arrays II
Сложность: easy

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

Пример:
Input: nums1 = [1,2,2,1], nums2 = [2,2]
Output: [2,2]


👨‍💻 Алгоритм:

1⃣Подсчет частоты элементов:
Используйте хеш-таблицу или словарь для подсчета количества вхождений каждого элемента в nums1.

2⃣Нахождение пересечения:
Пройдите по элементам nums2, и если элемент присутствует в хеш-таблице из шага 1 и его счетчик больше нуля, добавьте этот элемент в результат и уменьшите счетчик.

3⃣Возврат результата:
Верните массив пересечения.

😎 Решение:
from collections import Counter

class Solution:
def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
counts = Counter(nums1)
result = []

for num in nums2:
if counts[num] > 0:
result.append(num)
counts[num] -= 1

return result


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Задача: 476. Number Complement
Сложность: easy

Дополнение целого числа — это число, которое получается при замене всех 0 на 1 и всех 1 на 0 в его двоичном представлении.

Например, целое число 5 в двоичной системе — "101", и его дополнение — "010", что соответствует целому числу 2. Дано целое число num, верните его дополнение.

Пример:
Input: num = 5
Output: 2
Explanation: The binary representation of 5 is 101 (no leading zero bits), and its complement is 010. So you need to output 2.


👨‍💻 Алгоритм:

1⃣Вычислите длину в битах входного числа: l=⌊log 2 (num)⌋+1.

2⃣Постройте битовую маску из 1-битов длины l: bitmask=(1≪l)−1.

3⃣Верните результат операции XOR числа и битовой маски: num⊕bitmask num⊕bitmask.

😎 Решение:
class Solution:
def findComplement(self, num: int) -> int:
bitmask = num
bitmask |= (bitmask >> 1)
bitmask |= (bitmask >> 2)
bitmask |= (bitmask >> 4)
bitmask |= (bitmask >> 8)
bitmask |= (bitmask >> 16)
return bitmask ^ num


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Задача: 387. First Unique Character in a String
Сложность: easy

Дана строка s, найдите первый неповторяющийся символ в ней и верните его индекс. Если такого символа не существует, верните -1.

Пример:
Input: s = "leetcode"
Output: 0


👨‍💻 Алгоритм:

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

2⃣Пройдите по строке снова и проверьте для каждого символа, является ли его количество появлений в хеш-таблице равным 1.

3⃣Если найдется символ с количеством появлений, равным 1, верните его индекс. Если такой символ не найден, верните -1.

😎 Решение:
import random

class Solution:
def __init__(self, nums: list[int]):
self.original = nums[:]
self.array = nums[:]

def reset(self) -> list[int]:
self.array = self.original[:]
return self.original

def shuffle(self) -> list[int]:
n = len(self.array)
for i in range(n):
rand_index = random.randint(i, n - 1)
self.array[i], self.array[rand_index] = self.array[rand_index], self.array[i]
return self.array


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Задача: 1402. Reducing Dishes
Сложность: hard

Шеф-повар собрал данные об уровне удовлетворенности от своих n блюд. Шеф может приготовить любое блюдо за 1 единицу времени.

Коэффициент удовольствия от блюда определяется как время, затраченное на приготовление этого блюда вместе с предыдущими блюдами, умноженное на уровень удовлетворенности от этого блюда, то есть time[i] * satisfaction[i].

Верните максимальную сумму коэффициентов удовольствия, которую шеф-повар может получить после приготовления некоторого количества блюд.

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

Пример:
Input: satisfaction = [-1,-8,0,5,-9]
Output: 14
Explanation: After Removing the second and last dish, the maximum total like-time coefficient will be equal to (-1*1 + 0*2 + 5*3 = 14).
Each dish is prepared in one unit of time.


👨‍💻 Алгоритм:

1⃣Отсортируйте массив satisfaction в порядке возрастания.

2⃣Создайте таблицу мемоизации memo размером N x N и инициализируйте все значения -1, что будет означать, что ответ для всех состояний еще не рассчитан.

3⃣Реализуйте функцию, которая вызывается с параметрами index = 0 и time = 1, чтобы найти ответ:
Если достигнут конец массива, т.е. index == satisfaction.length, верните 0, так как больше нет блюд для приготовления и нельзя получить дополнительное значение.
Если значение в массиве memo для пары {index, time} не равно -1, верните это значение, так как это подразумевает, что данная подзадача уже была решена; поэтому рекурсивный вызов не требуется, и можно вернуть сохраненное значение из таблицы memo.
Рассчитайте максимум из двух вариантов:
- добавьте значение коэффициента для данного блюда satisfaction[index] * time к рекурсивному результату с index = index + 1 и time = time + 1.
- пропустите текущее блюдо и сделайте рекурсивный вызов для index = index + 1 и time = time.

😎 Решение:
class Solution:
def maxSatisfaction(self, satisfaction):
satisfaction.sort()
memo = [[-1] * (len(satisfaction) + 1) for _ in range(len(satisfaction) + 1)]

def findMaxSatisfaction(satisfaction, memo, index, time):
if index == len(satisfaction):
return 0
if memo[index][time] != -1:
return memo[index][time]

memo[index][time] = max(satisfaction[index] * time + findMaxSatisfaction(satisfaction, memo, index + 1, time + 1),
findMaxSatisfaction(satisfaction, memo, index + 1, time))
return memo[index][time]

return findMaxSatisfaction(satisfaction, memo, 0, 1)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Forwarded from easyoffer
📅 Осталось 7 дней до конца краудфандинга

Мы на финишной прямой!

Если ты планировал присоединиться, но ещё не успел, сейчас идеальный момент.

Вознаграждения за поддержку:

🚀 PRO подписка к easyoffer 2.0 на 1 год по цене месячной подписки. Активировать подписку можно в любой момент, например, когда начнешь искать работу.
Приглашение на закрытое бета-тестирование

👉 Поддержать easyoffer 2.0

Не откладывай на последний момент

📌 Если не получается оплатить через карту РФ — напишите мне @kivaiko, и мы найдём удобный способ
🔥2
Задача: 135. Candy
Сложность: hard

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

Вы раздаете конфеты этим детям с соблюдением следующих требований:

Каждый ребенок должен получить как минимум одну конфету.
Дети с более высоким рейтингом должны получать больше конфет, чем их соседи.
Верните минимальное количество конфет, которое вам нужно иметь, чтобы распределить их среди детей.

Пример:
Input: ratings = [1,0,2]
Output: 5
Explanation: You can allocate to the first, second and third child with 2, 1, 2 candies respectively.


👨‍💻 Алгоритм:

1️⃣Инициализация и первичное заполнение массивов:
Создайте два массива: left2right для расчета конфет с учетом только левых соседей и right2left для расчета с учетом только правых соседей. Изначально каждому ученику в обоих массивах присваивается по одной конфете.

2️⃣Обход и обновление значений в массивах:
Проходите массив ratings слева направо, увеличивая значение в left2right для каждого ученика, чей рейтинг выше рейтинга его левого соседа. Затем проходите массив справа налево, увеличивая значение в right2left для каждого ученика, чей рейтинг выше рейтинга его правого соседа.

3️⃣Расчет минимального количества конфет:
Для каждого ученика определите максимальное значение конфет между left2right[i] и right2left[i], чтобы соответствовать требованиям к распределению конфет. Суммируйте полученные значения для всех учеников, чтобы найти минимальное количество конфет, необходимое для соблюдения всех правил.

😎 Решение:
class Solution:
def candy(self, ratings: List[int]) -> int:
sum = 0
n = len(ratings)
left2right = [1] * n
right2left = [1] * n
for i in range(1, n):
if ratings[i] > ratings[i - 1]:
left2right[i] = left2right[i - 1] + 1
for i in range(n - 2, -1, -1):
if ratings[i] > ratings[i + 1]:
right2left[i] = right2left[i + 1] + 1
for i in range(n):
sum += max(left2right[i], right2left[i])
return sum


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Задача: 143. Reorder List
Сложность: medium

Вам дана голова односвязного списка. Список можно представить в следующем виде:
L0 → L1 → … → Ln - 1 → Ln
Переупорядочите список так, чтобы он принял следующую форму:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
Вы не можете изменять значения в узлах списка. Можно изменять только сами узлы.

Пример:
Input: head = [1,2,3,4]
Output: [1,4,2,3]


👨‍💻 Алгоритм:

1️⃣Нахождение середины списка и разделение его на две части: Используйте два указателя, slow и fast, для нахождения середины списка. Указатель slow движется на один узел за шаг, а fast — на два узла. Когда fast достигает конца списка, slow окажется в середине. Разделите список на две части. Первая часть начинается от головы списка до slow, вторая — с узла после slow до конца списка.

2️⃣Реверс второй половины списка: Инициализируйте указатели prev как NULL и curr как slow. Перемещайтесь по второй половине списка и меняйте направление ссылок между узлами для реверсирования списка. Продолжайте, пока не перестроите весь второй сегмент, теперь последний элемент первой части списка будет указывать на NULL, а prev станет новой головой второй половины списка.

3️⃣Слияние двух частей списка в заданном порядке: Начните с головы первой части списка (first) и головы реверсированной второй части (second). Перекрестно связывайте узлы из первой и второй части, вставляя узлы из второй части между узлами первой части. Передвигайте указатели first и second соответственно после каждой вставки. Продолжайте этот процесс до тех пор, пока узлы второй части не закончатся.

😎 Решение:
class Solution:
def reorderList(self, head: ListNode) -> None:
if not head:
return

slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next

prev, curr = None, slow
while curr:
curr.next, prev, curr = prev, curr, curr.next

first, second = head, prev
while second.next:
first.next, first = second, first.next
second.next, second = first, second.next


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Задача: 61. Rotate List
Сложность: medium

Дан указатель на начало связного списка, поверните список вправо на k позиций.

Пример:
Input: head = [0,1,2], k = 4
Output: [2,0,1]


👨‍💻 Алгоритм:

1️⃣Найдите старый хвост и соедините его с головой (old_tail.next = head), чтобы замкнуть кольцо. Одновременно вычислите длину списка n.

2️⃣Найдите новый хвост, который находится на позиции (n - k % n - 1) от головы, и новую голову, которая находится на позиции (n - k % n).

3️⃣Разорвите кольцо (new_tail.next = None) и верните new_head.

😎 Решение:
class Solution:
def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
if not head:
return None
if not head.next:
return head

old_tail = head
n = 1
while old_tail.next:
old_tail = old_tail.next
n += 1
old_tail.next = head

new_tail = head
for i in range(n - k % n - 1):
new_tail = new_tail.next
new_head = new_tail.next

new_tail.next = None

return new_head


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Задача: 111. Minimum Depth of Binary Tree
Сложность: easy

Дано бинарное дерево, найдите его минимальную глубину.

Минимальная глубина - это количество узлов вдоль самого короткого пути от корневого узла до ближайшего листового узла.

Пример:
Input: root = [3,9,20,null,null,15,7]
Output: 2


👨‍💻 Алгоритм:

1️⃣Мы будем использовать метод обхода в глубину (dfs) с корнем в качестве аргумента.
Базовое условие рекурсии: это для узла NULL, в этом случае мы должны вернуть 0.

2️⃣Если левый ребенок корня является NULL: тогда мы должны вернуть 1 + минимальную глубину для правого ребенка корневого узла, что равно 1 + dfs(root.right).

3️⃣Если правый ребенок корня является NULL: тогда мы должны вернуть 1 + минимальную глубину для левого ребенка корневого узла, что равно 1 + dfs(root.left). Если оба ребенка не являются NULL, тогда вернуть 1 + min(dfs(root.left), dfs(root.right)).

😎 Решение:
class Solution:
def minDepth(self, root):
def dfs(root):
if root is None:
return 0
if root.left is None:
return 1 + dfs(root.right)
elif root.right is None:
return 1 + dfs(root.left)
return 1 + min(dfs(root.left), dfs(root.right))

return dfs(root)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Задача: 1047. Remove All Adjacent Duplicates In String
Сложность: easy

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

Пример:
Input: stones = [2,7,4,1,8,1]
Output: 1


👨‍💻 Алгоритм:

1⃣Создай пустой стек для хранения символов строки.

2⃣Проходи по символам строки, добавляя каждый символ в стек, если он не совпадает с верхним элементом стека, иначе удаляй верхний элемент.

3⃣После прохождения по строке, собери оставшиеся символы в стеке в результирующую строку и верни ее.

😎 Решение:
def removeDuplicates(s: str) -> str:
stack = []
for char in s:
if stack and stack[-1] == char:
stack.pop()
else:
stack.append(char)
return ''.join(stack)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Задача: 383. Ransom Note
Сложность: easy

Даны две строки ransomNote и magazine, верните true, если ransomNote можно составить, используя буквы из magazine, и false в противном случае.

Каждая буква из magazine может быть использована в ransomNote только один раз.

Пример:
Input: ransomNote = "a", magazine = "b"
Output: false


👨‍💻 Алгоритм:

1⃣Поскольку строки являются неизменяемым типом, их нельзя изменять, поэтому у них нет операций "вставки" и "удаления".

2⃣По этой причине необходимо заменять строку magazine новой строкой, в которой отсутствует символ, который мы хотели удалить.

3⃣Повторяйте этот процесс, пока не будут удалены все необходимые символы.

😎 Решение:
def canConstruct(ransomNote: str, magazine: str) -> bool:
for char in ransomNote:
index = magazine.find(char)
if index == -1:
return false
magazine = magazine[:index] + magazine[index + 1:]
return True


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Forwarded from easyoffer
Офигеть, вот это поддержка! 🔥

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

Но больше всего я боялся, что запущу кампанию, и не получится собрать даже 300 т. Это был бы провал. Так много усилий, времени и денег вложено в проект… и если бы всё закончилось ничем — это бы сильно демотивировало.

Но, ребята, мы превысили изначальную цель в 10 раз —
3 031 040 рублей! 🤯

Вся эта кампания — это одна большая проверка бизнес-модели на прочность. И я супер рад, что запустил всё публично. Люди видят, что EasyOffer реально нужен. Теперь нет сомнений — проект актуален, он будет прибыльным и будет развиваться.

Мне приходит огромное количество сообщений в личку: кто-то когда-то давно пользовался сайтом, он помог с трудоустройством, и сейчас они уже не ищут работу — но всё равно поддержали.
Это прям очень круто и трогательно.

Никак не могу отделаться от мысли, что easyoffer — это ведь мой первый сайт. Учебный, пет-проект, просто для портфолио. И вот что из него вышло. Просто офигеть.

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

Огромное спасибо за вашу поддержку! ❤️
🔥3
Задача: 462. Minimum Moves to Equal Array Elements II
Сложность: medium

Дан массив целых чисел nums размера n, вернуть минимальное количество ходов, необходимых для того, чтобы сделать все элементы массива равными.

В одном ходе вы можете увеличить или уменьшить элемент массива на 1.

Тестовые случаи составлены так, что ответ поместится в 32-битное целое число.

Пример:
Input: nums = [1,2,3]
Output: 2
Explanation:
Only two moves are needed (remember each move increments or decrements one element):
[1,2,3] => [2,2,3] => [2,2,2]


👨‍💻 Алгоритм:

1⃣Найти минимальный и максимальный элементы в массиве. Пусть k будет числом, к которому должны быть приведены все элементы массива.

2⃣Перебирать значения k в диапазоне между минимальным и максимальным элементами, вычисляя количество ходов, необходимых для каждого k.

3⃣Определить минимальное количество ходов среди всех возможных k, что и будет конечным результатом.

😎 Решение:
class Solution:
def minMoves2(self, nums: List[int]) -> int:
ans = float('inf')
minval = min(nums)
maxval = max(nums)
for i in range(minval, maxval + 1):
sum_moves = 0
for num in nums:
sum_moves += abs(num - i)
ans = min(ans, sum_moves)
return int(ans)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1