Python | LeetCode
9.98K subscribers
167 photos
2 videos
1.13K links
Cайт easyoffer.ru
Реклама @easyoffer_adv
ВП @easyoffer_vp

Тесты t.me/+20tRfhrwPpM4NDQy
Вопросы собесов t.me/+cnJC0_ZeZ_I0OGY6
Вакансии t.me/+cXGKkrOY2-w3ZTky
Download Telegram
Задача: 560. Subarray Sum Equals K
Сложность: medium

Дан массив целых чисел nums и целое число k, вернуть общее количество подмассивов, сумма которых равна k.

Подмассив - это непрерывная непустая последовательность элементов внутри массива.

Пример:
Input: nums = [1,1,1], k = 2
Output: 2


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

1⃣Самый простой метод - рассмотреть каждый возможный подмассив данного массива nums.

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

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

😎 Решение:
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
count = 0
for start in range(len(nums)):
for end in range(start + 1, len(nums) + 1):
sum_ = sum(nums[start:end])
if sum_ == k:
count += 1
return count


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1214. Two Sum BSTs
Сложность: medium

Даны корни двух бинарных деревьев поиска, root1 и root2, верните true, если и только если существует узел в первом дереве и узел во втором дереве, значения которых в сумме равны заданному целому числу target.

Пример:
Input: root1 = [0,-10,10], root2 = [5,1,7,0,2], target = 18
Output: false


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

1⃣Создайте два пустых множества node_set1 и node_set2. Выполните обход дерева root1, добавляя значения каждого узла в node_set1, и выполните обход дерева root2, добавляя значения каждого узла в node_set2.

2⃣Итерация по элементам в node_set1: для каждого элемента value1 проверяйте, находится ли target - value1 в node_set2.

3⃣Если target - value1 находится в node_set2, верните true. Если после завершения итерации не найдено ни одной подходящей пары, верните false.

😎 Решение:
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right

class Solution:
def dfs(self, node, node_set):
if not node:
return
self.dfs(node.left, node_set)
node_set.add(node.val)
self.dfs(node.right, node_set)

def twoSumBSTs(self, root1, root2, target):
node_set1 = set()
node_set2 = set()
self.dfs(root1, node_set1)
self.dfs(root2, node_set2)

for value1 in node_set1:
if target - value1 in node_set2:
return True

return False


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 369. Plus One Linked List
Сложность: hard

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

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

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


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

1️⃣Инициализируйте стражевой узел как ListNode(0) и установите его как новую голову списка: sentinel.next = head. Найдите крайний правый элемент, не равный девяти.

2️⃣Увеличьте найденную цифру на единицу и установите все следующие девятки в ноль.

3️⃣Верните sentinel, если его значение было установлено на 1, иначе верните head (sentinel.next).

😎 Решение:
class Solution:
def plusOne(self, head: ListNode) -> ListNode:
# sentinel head
sentinel = ListNode(0)
sentinel.next = head
not_nine = sentinel

# find the rightmost not-nine digit
while head:
if head.val != 9:
not_nine = head
head = head.next

# increase this rightmost not-nine digit by 1
not_nine.val += 1
not_nine = not_nine.next

# set all the following nines to zeros
while not_nine:
not_nine.val = 0
not_nine = not_nine.next

return sentinel if sentinel.val else sentinel.next


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 25. Reverse Nodes in k-Group
Сложность: hard

Учитывая заголовок связанного списка, поменяйте местами узлы списка k за раз и верните измененный список.

k — целое положительное число, меньшее или равное длине связанного списка. Если количество узлов не кратно k, то пропущенные узлы в конечном итоге должны остаться такими, какие они есть.

Вы не можете изменять значения в узлах списка, можно изменять только сами узлы.

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


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

1️⃣Проходим по списку, находя группы из k узлов.

2️⃣Разворачиваем найденную группу, изменяя ссылки между узлами.

3️⃣Повторяем процесс, пока не обработаем весь список.

😎 Решение:
class Solution:  
def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
if k == 1:
return head

def reverse(first, last, pre_first):
nonlocal head
if pre_first:
pre_first.next = last
else:
head = last

prev, curr = first, first.next
first.next = last.next
for _ in range(k-1):
curr.next, prev, curr = prev, curr, curr.next

count = 1
curr = first = head
pre_first = None
while curr:
if count == k:
reverse(first, curr, pre_first)
pre_first = first
curr, first = first.next, first.next
count = 1
else:
curr = curr.next
count += 1

return head


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

Даны два вектора целых чисел v1 и v2, реализуйте итератор, который возвращает их элементы поочередно.

Реализуйте класс ZigzagIterator:
ZigzagIterator(List<int> v1, List<int> v2) инициализирует объект с двумя векторами v1 и v2.
boolean hasNext() возвращает true, если в итераторе еще есть элементы, и false в противном случае.
int next() возвращает текущий элемент итератора и перемещает итератор к следующему элементу.

Пример:
Input: v1 = [1,2], v2 = [3,4,5,6]
Output: [1,3,2,4,5,6]
Explanation: By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,3,2,4,5,6].


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

1⃣Инициализация объекта:
Создайте класс ZigzagIterator с двумя списками v1 и v2. Сохраните эти списки в структуре vectors.
Инициализируйте очередь queue, содержащую пары индексов: индекс списка и индекс элемента в этом списке, если список не пуст.

2⃣Метод next:
Удалите первую пару индексов из очереди.
Извлеките элемент из соответствующего списка по указанным индексам.
Если в текущем списке есть еще элементы, добавьте новую пару индексов (тот же список, следующий элемент) в конец очереди.
Верните извлеченный элемент.

3⃣Метод hasNext:
Проверьте, пуста ли очередь.
Верните true, если в очереди есть элементы, и false в противном случае.

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

class ZigzagIterator:
def __init__(self, v1, v2):
self.vectors = [v1, v2]
self.queue = deque((i, 0) for i, vec in enumerate(self.vectors) if vec)

def next(self):
vecIndex, elemIndex = self.queue.popleft()
if elemIndex + 1 < len(self.vectors[vecIndex]):
self.queue.append((vecIndex, elemIndex + 1))
return self.vectors[vecIndex][elemIndex]

def hasNext(self):
return bool(self.queue)


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

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

Реализуйте класс NestedIterator:

NestedIterator(List<NestedInteger> nestedList) Инициализирует итератор вложенным списком nestedList.
int next() Возвращает следующий целый элемент вложенного списка.
boolean hasNext() Возвращает true, если в вложенном списке еще остались целые числа, и false в противном случае.

Пример:
Input: nestedList = [[1,1],2,[1,1]]
Output: [1,1,2,1,1]
Explanation: By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,1,2,1,1].


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

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

2⃣Метод next()
Возвращает следующий целый элемент из стека или очереди. Если текущий элемент является списком, развёртывайте его и добавляйте элементы в стек.

3⃣Метод hasNext()
Проверяет, есть ли в стеке или очереди оставшиеся целые элементы. Если на вершине стека находится список, развёртывайте его до тех пор, пока не встретится целый элемент.

😎 Решение:
class NestedIterator:
def __init__(self, nestedList: [NestedInteger]):
self.stack = []
self._flatten(nestedList)

def _flatten(self, nestedList):
for ni in reversed(nestedList):
self.stack.append(ni)

def next(self) -> int:
return self.stack.pop().getInteger()

def hasNext(self) -> bool:
while self.stack and not self.stack[-1].isInteger():
self._flatten(self.stack.pop().getList())
return bool(self.stack)


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

Дан массив интервалов времени встреч, где intervals[i] = [starti, endi]. Определите, может ли человек посетить все встречи.

Пример:
Input: intervals = [[0,30],[5,10],[15,20]]
Output: false


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

1️⃣Создайте функцию для проверки перекрытия двух интервалов:
Возвращайте true, если начало одного интервала находится внутри другого интервала.

2️⃣Проверьте каждый интервал с каждым другим интервалом:
Если найдено перекрытие, верните false.

3️⃣Если все интервалы проверены и перекрытий не найдено, верните true.

😎 Решение:
class Solution:
def canAttendMeetings(self, intervals: List[List[int]]) -> bool:
def overlap(interval1: List[int], interval2: List[int]) -> bool:
return (interval1[0] >= interval2[0] and interval1[0] < interval2[1]
or interval2[0] >= interval1[0] and interval2[0] < interval1[1])

for i in range(len(intervals)):
for j in range(i + 1, len(intervals)):
if overlap(intervals[i], intervals[j]):
return False
return True


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Задача: 1046. Last Stone Weight
Сложность: easy

Вам дан массив целых чисел stones, где stones[i] - вес i-го камня. Мы играем в игру с камнями. На каждом ходу мы выбираем два самых тяжелых камня и разбиваем их вместе. Предположим, что два самых тяжелых камня имеют веса x и y, причем x <= y. Результат разбивания таков: если x == y, оба камня уничтожаются, а если x != y, камень веса x уничтожается, а камень веса y имеет новый вес y - x. В конце игры остается не более одного камня. Верните вес последнего оставшегося камня. Если камней не осталось, верните 0.

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


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

1⃣Создай максимальную кучу из массива камней.

2⃣Извлекай два самых тяжелых камня, разбивай их, и, если необходимо, возвращай оставшийся камень обратно в кучу.

3⃣Повторяй шаг 2, пока не останется один или ноль камней, и верни вес последнего оставшегося камня или 0, если камней не осталось.

😎 Решение:
import heapq

def lastStoneWeight(stones):
stones = [-stone for stone in stones]
heapq.heapify(stones)

while len(stones) > 1:
first = -heapq.heappop(stones)
second = -heapq.heappop(stones)
if first != second:
heapq.heappush(stones, -(first - second))

return -stones[0] if stones else 0


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

Дана строка, представляющая фрагмент кода, реализуйте валидатор тегов для разбора кода и определения его корректности.

Фрагмент кода считается корректным, если соблюдаются все следующие правила:
Код должен быть заключен в корректный закрытый тег. В противном случае код некорректен.
Закрытый тег (не обязательно корректный) имеет точно следующий формат: <TAG_NAME>TAG_CONTENT</TAG_NAME>. Среди них <TAG_NAME> — это начальный тег, а </TAG_NAME> — конечный тег. TAG_NAME в начальном и конечном тегах должен быть одинаковым. Закрытый тег корректен, если и только если TAG_NAME и TAG_CONTENT корректны.
Корректное TAG_NAME содержит только заглавные буквы и имеет длину в диапазоне [1, 9]. В противном случае TAG_NAME некорректен.
Корректное TAG_CONTENT может содержать другие корректные закрытые теги, cdata и любые символы (см. примечание 1), КРОМЕ неподходящих <, неподходящих начальных и конечных тегов, и неподходящих или закрытых тегов с некорректным TAG_NAME. В противном случае TAG_CONTENT некорректен.
Начальный тег неподходящий, если нет конечного тега с тем же TAG_NAME, и наоборот. Однако нужно также учитывать проблему несбалансированных тегов, когда они вложены.
< неподходящий, если не удается найти последующий >. И когда вы находите < или </, все последующие символы до следующего > должны быть разобраны как TAG_NAME (не обязательно корректный).
cdata имеет следующий формат: <![CDATA[CDATA_CONTENT]]>. Диапазон CDATA_CONTENT определяется как символы между <![CDATA[ и первым последующим ]]>.
CDATA_CONTENT может содержать любые символы. Функция cdata заключается в том, чтобы запретить валидатору разбирать CDATA_CONTENT, поэтому даже если в нем есть символы, которые могут быть разобраны как тег (корректный или некорректный), вы должны рассматривать их как обычные символы.

Пример:
Input: code = "<DIV>This is the first line <![CDATA[<div>]]></DIV>"
Output: true


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

1⃣Инициализируйте стек для отслеживания открытых тегов и флаг для определения наличия тегов. Используйте регулярное выражение для проверки корректности TAG_NAME, TAG_CONTENT и CDATA.

2⃣Пройдитесь по строке, проверяя каждый символ. Если встретите <, определите тип тега (начальный, конечный или CDATA). Обновите стек и индексы в зависимости от найденного типа.

3⃣В конце проверьте, что стек пуст (все теги корректно закрыты) и верните результат.

😎 Решение:
import re

class Solution:
def __init__(self):
self.stack = []
self.contains_tag = False

def is_valid_tag_name(self, s, ending):
if ending:
if self.stack and self.stack[-1] == s:
self.stack.pop()
else:
return False
else:
self.contains_tag = True
self.stack.append(s)
return True

def isValid(self, code: str) -> bool:
pattern = re.compile(r"<[A-Z]{0,9}>([^<]*(<((\/?[A-Z]{1,9}>)|(!\[CDATA\[.*?\]\]>)))?)*")
if not pattern.fullmatch(code):
return False

i = 0
while i < len(code):
ending = False
if not self.stack and self.contains_tag:
return False
if code[i] == '<':
if code[i + 1] == '!':
i = code.find("]]>", i + 1)
if i == -1:
return False
continue
if code[i + 1] == '/':
i += 1
ending = True
close_index = code.find('>', i + 1)
if close_index == -1 or not self.is_valid_tag_name(code[i + 1:close_index], ending):
return False
i = close_index
i += 1
return not self.stack


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 658. Find K Closest Elements
Сложность: easy

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

Целое число a ближе к x, чем целое число b, если:

|a - x| < |b - x|, или
|a - x| == |b - x| и a < b.

Пример:
Input: arr = [1,2,3,4,5], k = 4, x = 3
Output: [1,2,3,4]


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

1⃣Бинарный поиск:
Найдите положение числа x или ближайшего к нему числа в массиве arr с помощью бинарного поиска.

2⃣Два указателя:
Используйте два указателя, чтобы расширять окно, которое содержит k ближайших к x элементов. Начните с ближайших элементов и расширяйте окно, сравнивая элементы слева и справа от текущего окна.

3⃣Сортировка:
Отсортируйте итоговый список, если это необходимо (в данном случае это не нужно, так как массив уже отсортирован).

😎 Решение:
import bisect

class Solution:
def findClosestElements(self, arr: List[int], k: int, x: int) -> List[int]:
pos = bisect.bisect_left(arr, x)
left, right = pos - 1, pos

while right - left - 1 < k:
if left == -1:
right += 1
elif right == len(arr) or (x - arr[left] <= arr[right] - x):
left -= 1
else:
right += 1

return arr[left + 1:right]


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1482. Minimum Number of Days to Make m Bouquets
Сложность: medium

Вам дан массив целых чисел bloomDay, целое число m и целое число k.

Вам нужно сделать m букетов. Для создания букета необходимо использовать k соседних цветов из сада.
Сад состоит из n цветов, i-й цветок расцветет на bloomDay[i] и затем может быть использован ровно в одном букете.

Верните минимальное количество дней, которое нужно подождать, чтобы можно было сделать m букетов из сада. Если сделать m букетов невозможно, верните -1.

Пример:
Input: bloomDay = [1,10,3,10,2], m = 3, k = 1
Output: 3
Explanation: Let us see what happened in the first three days. x means flower bloomed and _ means flower did not bloom in the garden.
We need 3 bouquets each should contain 1 flower.
After day 1: [x, _, _, _, _] // we can only make one bouquet.
After day 2: [x, _, _, _, x] // we can only make two bouquets.
After day 3: [x, _, x, _, x] // we can make 3 bouquets. The answer is 3.


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

1⃣Инициализация:
Инициализируйте start как 0 и end как максимальное значение в массиве bloomDay.
Введите вспомогательную функцию getNumOfBouquets для подсчета количества букетов, которые можно сделать на определенный день.

2⃣Поиск минимального числа дней:
Выполняйте бинарный поиск, пока start меньше или равен end:
- рассчитайте mid как среднее значение между start и end.
- используйте getNumOfBouquets, чтобы определить, сколько букетов можно сделать на mid день.
- если количество букетов больше или равно m, сохраните mid как возможное решение и переместите end влево.
- иначе переместите start вправо.

3⃣Возвращение результата:
Верните найденное минимальное количество дней или -1, если сделать m букетов невозможно.

😎 Решение:
class Solution:
def getNumOfBouquets(self, bloomDay, mid, k):
numOfBouquets = 0
count = 0
for day in bloomDay:
if day <= mid:
count += 1
else:
count = 0
if count == k:
numOfBouquets += 1
count = 0
return numOfBouquets

def minDays(self, bloomDay, m, k):
if len(bloomDay) < m * k:
return -1
start, end = 0, max(bloomDay)
minDays = -1
while start <= end:
mid = (start + end) // 2
if self.getNumOfBouquets(bloomDay, mid, k) >= m:
minDays = mid
end = mid - 1
else:
start = mid + 1
return minDays


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: №22. Generate Parentheses
Сложность: medium

Учитывая n пар круглых скобок, напишите функцию, которая генерирует все комбинации правильных круглых скобок.

Пример:
Input: n = 3  
Output: ["((()))","(()())","(())()","()(())","()()()"]


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

1️⃣Используем рекурсию (DFS) для генерации всех возможных комбинаций.

2️⃣Добавляем открывающую скобку, если их количество меньше n.

3️⃣Добавляем закрывающую скобку, если их количество меньше, чем открывающих.

😎 Решение:
class Solution:
def generateParenthesis(self, n: int):
def dfs(left, right, s):
if len(s) == n * 2:
res.append(s)
return

if left < n:
dfs(left + 1, right, s + '(')
if right < left:
dfs(left, right + 1, s + ')')

res = []
dfs(0, 0, '')
return res


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