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

Тесты t.me/+20tRfhrwPpM4NDQy
Вопросы собесов t.me/+cnJC0_ZeZ_I0OGY6
Вакансии t.me/+cXGKkrOY2-w3ZTky
Download Telegram
#hard
Задача: 446. Arithmetic Slices II - Subsequence


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

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

Например, [1, 3, 5, 7, 9], [7, 7, 7, 7] и [3, -1, -5, -9] являются арифметическими последовательностями.
Например, [1, 1, 2, 5, 7] не является арифметической последовательностью.
Подпоследовательность массива - это последовательность, которая может быть образована путем удаления некоторых элементов (возможно, ни одного) из массива.

Например, [2, 5, 10] является подпоследовательностью [1, 2, 1, 2, 4, 1, 5, 10].
Тестовые случаи сгенерированы таким образом, что ответ помещается в 32-битное целое число.

Пример:
Input: nums = [2,4,6,8,10]
Output: 7
Explanation: All arithmetic subsequence slices are:
[2,4,6]
[4,6,8]
[6,8,10]
[2,4,6,8]
[4,6,8,10]
[2,4,6,8,10]
[2,6,10]


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

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

2⃣Мы можем проверить, является ли подпоследовательность арифметической, согласно ее определению.

3⃣Возвращаем количество всех арифметических подпоследовательностей.

😎 Решение:
class Solution:
def __init__(self):
self.n = 0
self.ans = 0

def dfs(self, dep, A, cur):
if dep == self.n:
if len(cur) < 3:
return
for i in range(1, len(cur)):
if cur[i] - cur[i - 1] != cur[1] - cur[0]:
return
self.ans += 1
return
self.dfs(dep + 1, A, cur)
cur.append(A[dep])
self.dfs(dep + 1, A, cur)
cur.pop()

def numberOfArithmeticSlices(self, A):
self.n = len(A)
self.ans = 0
self.dfs(0, A, [])
return self.ans


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1
#medium
Задача: 364. Nested List Weight Sum II

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

Глубина целого числа — это количество списков, внутри которых оно находится. Например, вложенный список [1,[2,2],[[3],2],1] имеет значение каждого целого числа, установленное равным его глубине. Пусть maxDepth будет максимальной глубиной любого целого числа.
Вес целого числа определяется как maxDepth - (глубина целого числа) + 1.

Верните сумму каждого целого числа в nestedList, умноженную на его вес.

Пример:
Input: nestedList = [[1,1],2,[1,1]]
Output: 8
Explanation: Four 1's with a weight of 1, one 2 with a weight of 2.
1*1 + 1*1 + 2*2 + 1*1 + 1*1 = 8


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

1⃣Инициализировать первый уровень BFS-дерева, добавив все элементы из входного nestedList в очередь.

2⃣Для каждого уровня извлекать передний элемент из очереди. Если это список, то добавить его элементы в очередь. В противном случае обновить значения sumOfElements, maxDepth и sumOfProducts.

3⃣Когда очередь станет пустой, вернуть значение (maxDepth + 1) * sumOfElements - sumOfProducts.

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

class Solution:
def depthSumInverse(self, nestedList):
queue = deque(nestedList)
depth = 1
maxDepth = 0
sumOfElements = 0
sumOfProducts = 0

while queue:
size = len(queue)
maxDepth = max(maxDepth, depth)

for _ in range(size):
nested = queue.popleft()

if nested.isInteger():
value = nested.getInteger()
sumOfElements += value
sumOfProducts += value * depth
else:
queue.extend(nested.getList())
depth += 1
return (maxDepth + 1) * sumOfElements - sumOfProducts


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2
#medium
Задача: 366. Find Leaves of Binary Tree

Дан корень бинарного дерева, соберите узлы дерева следующим образом:
Соберите все листовые узлы.
Удалите все листовые узлы.
Повторяйте, пока дерево не станет пустым.

Пример:
Input: root = [1,2,3,4,5]
Output: [[4,5,3],[2],[1]]
Explanation:
[[3,5,4],[2],[1]] and [[3,4,5],[2],[1]] are also considered correct answers since per each level it does not matter the order on which elements are returned.


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

1⃣Реализовать функцию getHeight(node), которая будет вычислять высоту каждого узла в дереве с использованием рекурсивного обхода в глубину (post-order). Если узел является null, вернуть -1.

2⃣Сохранить пары (высота, значение) для всех узлов и отсортировать их по высоте.

3⃣Организовать узлы по высоте и вернуть результат.

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

class Solution:
def __init__(self):
self.pairs = []

def getHeight(self, node):
if not node:
return -1
leftHeight = self.getHeight(node.left)
rightHeight = self.getHeight(node.right)
currHeight = max(leftHeight, rightHeight) + 1
self.pairs.append((currHeight, node.val))
return currHeight

def findLeaves(self, root):
self.getHeight(root)
self.pairs.sort()
solution = []
currentHeight = -1
for height, val in self.pairs:
if height != currentHeight:
solution.append([])
currentHeight = height
solution[-1].append(val)
return solution


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

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

Фрагмент кода считается корректным, если соблюдаются все следующие правила:
Код должен быть заключен в корректный закрытый тег. В противном случае код некорректен.
Закрытый тег (не обязательно корректный) имеет точно следующий формат: <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
1
#hard
Задача: 710. Random Pick with Blacklist

Вам дано целое число n и массив уникальных целых чисел blacklist. Разработайте алгоритм выбора случайного целого числа из диапазона [0, n - 1], не входящего в черный список. Любое целое число, находящееся в указанном диапазоне и не входящее в черный список, должно с равной вероятностью быть возвращено. Оптимизируйте алгоритм так, чтобы он минимизировал количество обращений к встроенной функции random вашего языка. Реализуйте класс Solution: Solution(int n, int[] blacklist) Инициализирует объект целым числом n и целым числом из черного списка blacklist. int pick() Возвращает случайное целое число в диапазоне [0, n - 1] и не входящее в черный список.

Пример:
Input
["Solution", "pick", "pick", "pick", "pick", "pick", "pick", "pick"]
[[7, [2, 3, 5]], [], [], [], [], [], [], []]
Output
[null, 0, 4, 1, 6, 1, 0, 4]


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

1⃣Создайте маппинг для чисел, входящих в черный список, чтобы сопоставить их с числами из диапазона [n - len(blacklist), n - 1], которые не входят в черный список.

2⃣Создайте массив для хранения возможных чисел для выбора, исключая числа из черного списка.

3⃣При каждом вызове функции pick() используйте встроенную функцию random для выбора случайного индекса из массива возможных чисел и возвращайте соответствующее значение.

😎 Решение:
import random

class Solution:
def __init__(self, n, blacklist):
self.mapping = {}
self.range_size = n - len(blacklist)
blacklist_set = set(blacklist)

last = n - 1
for b in blacklist:
if b < self.range_size:
while last in blacklist_set:
last -= 1
self.mapping[b] = last
last -= 1

def pick(self):
idx = random.randint(0, self.range_size - 1)
return self.mapping.get(idx, idx)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1
Forwarded from easyoffer
Привет, ребята!
1,5 года я учился на программиста, а сайт easyoffer.ru стал моим пет-проектом. Я создавал его, потому что:
а) нужно было добавить хоть какой-нибудь проект в резюме
б) подготовиться к прохождению собесов

И всё получилось! Благодаря еasyoffer я успешно прошёл собеседование и устроился Python Junior-разработчиком на удаленку с зарплатой 115 тысяч рублей.

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

По-этому я с самого начала заложил в проект минимальную бизнес-модель, на случай, если сайт начнёт набирать трафик. Я предложил пользователям полный доступ к сайту в обмен на подписку на Telegram-каналы. Это позволяло развивать аудиторию, а в будущем — зарабатывать на рекламе.

Результат превзошёл ожидания!
С момента запуска easyoffer посетило 400 тысяч человек. А когда доход с рекламы превысил мою зарплату программиста, я принял решение уйти с работы и полностью посвятить себя разработке новой версии сайта.

Вот так, зайдя в IT, через 4 месяца вышел через свой же пет-проект. Мне очень повезло

Уже год я работаю над easyoffer 2.0.
Это будет более масштабный и качественной новый проект:
– Появится тренажер
– Появятся задачи из собесов
– Фильтрация контента по грейдам
и еще очень много фич, о которых я расскажу позже.

Хочу, довести easyoffer до ума, чтобы сайт стал настоящим помощником для всех, кто готовится к собеседованиям.
По этому в ближайшее время я объявлю о старте краудфандинговой кампании, чтобы ускорить разработку и я готов щедро отблагодарить всех, кто поддержит проект.

А те, кто поддержат проект первыми, получат специальные лимитированные выгодные вознаграждения. Следите за этим телеграм каналом, если хотите стать первыми сапортерами.
1
#medium
Задача: 764. Largest Plus Sign

Вам дано целое число n. У вас есть бинарная сетка размером n x n, в которой все значения изначально равны 1, за исключением некоторых индексов, указанных в массиве mines. Элемент массива mines с индексом i определяется как mines[i] = [xi, yi], где grid[xi][yi] == 0.

Верните порядок самого большого крестообразного знака из 1, выровненного по осям, который содержится в сетке. Если такого знака нет, верните 0.

Крестообразный знак из 1 порядка k имеет некоторый центр grid[r][c] == 1, а также четыре луча длиной k - 1, идущих вверх, вниз, влево и вправо, состоящие из 1. Обратите внимание, что за пределами лучей креста могут быть 0 или 1, проверяется только соответствующая область крестообразного знака на наличие 1.

Пример:
Input: n = 5, mines = [[4,2]]
Output: 2
Explanation: In the above grid, the largest plus sign can only be of order 2. One of them is shown.


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

1⃣Создайте сетку размером n x n, заполненную единицами. Затем используйте массив mines, чтобы установить значения нулей в соответствующих ячейках сетки.

2⃣Для каждой ячейки в сетке создайте четыре дополнительных сетки: left, right, up и down, которые будут хранить длину непрерывных единиц, простирающихся в соответствующем направлении от каждой ячейки.

3⃣Пройдите по всей сетке и для каждой ячейки определите минимальную длину луча среди четырех направлений. Эта минимальная длина будет определять порядок крестообразного знака с центром в данной ячейке. Обновите максимальный порядок крестообразного знака и верните его после завершения обхода всей сетки. Если такого знака нет, верните 0.

😎 Решение:
class Solution:
def orderOfLargestPlusSign(self, N: int, mines: List[List[int]]) -> int:
banned = set()
for mine in mines:
banned.add(mine[0] * N + mine[1])

ans = 0
for r in range(N):
for c in range(N):
k = 0
while k <= r and r < N - k and k <= c and c < N - k and \
(r - k) * N + c not in banned and \
(r + k) * N + c not in banned and \
r * N + c - k not in banned and \
r * N + c + k not in banned:
k += 1
ans = max(ans, k)
return ans


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍2
#hard
Задача: 711. Number of Distinct Islands II

Вам дана двоичная матричная сетка m x n. Остров - это группа 1 (представляющая сушу), соединенных в четырех направлениях (горизонтальном или вертикальном). Можно предположить, что все четыре края сетки окружены водой. Остров считается одинаковым с другим, если они имеют одинаковую форму, или имеют одинаковую форму после поворота (только на 90, 180 или 270 градусов) или отражения (влево/вправо или вверх/вниз). Верните количество разных островов.

Пример:
Input: grid = [[1,1,0,0,0],[1,0,0,0,0],[0,0,0,0,1],[0,0,0,1,1]]
Output: 1


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

1⃣Пройдите по каждому элементу матрицы, если найдена земля (1), выполните DFS для обнаружения всех связанных с этим островом земель и сохраните форму острова.

2⃣Нормализуйте форму острова, применив все возможные повороты и отражения, чтобы найти каноническую форму.

3⃣Используйте множество для хранения всех уникальных канонических форм и верните размер этого множества.

😎 Решение:
def numDistinctIslands2(grid):
def dfs(i, j):
shape = []
stack = [(i, j)]
while stack:
x, y = stack.pop()
if 0 <= x < len(grid) and 0 <= y < len(grid[0]) and grid[x][y] == 1:
grid[x][y] = 0
shape.append((x - i, y - j))
stack.extend([(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)])
return shape

def normalize(shape):
shapes = [[] for _ in range(8)]
for x, y in shape:
shapes[0].append((x, y))
shapes[1].append((x, -y))
shapes[2].append((-x, y))
shapes[3].append((-x, -y))
shapes[4].append((y, x))
shapes[5].append((y, -x))
shapes[6].append((-y, x))
shapes[7].append((-y, -x))
for s in shapes:
s.sort()
return min(shapes)

unique_islands = set()
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 1:
shape = dfs(i, j)
unique_islands.add(tuple(normalize(shape)))

return len(unique_islands)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
#hard
Задача: 765. Couples Holding Hands

Есть n пар, сидящих на 2n местах, расположенных в ряд, и они хотят держаться за руки.

Люди и места представлены массивом целых чисел row, где row[i] — это ID человека, сидящего на i-м месте. Пары пронумерованы по порядку: первая пара — (0, 1), вторая пара — (2, 3) и так далее, до последней пары — (2n - 2, 2n - 1).

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

Пример:
Input: row = [0,2,1,3]
Output: 1
Explanation: We only need to swap the second (row[1]) and third (row[2]) person.


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

1⃣Мы могли бы предположить без доказательства, что решение, при котором мы делаем людей на каждом диване счастливыми по порядку, является оптимальным. Это предположение сильнее, чем гипотеза о жадном подходе, но кажется разумным, поскольку при каждом ходе мы делаем хотя бы одну пару счастливой.

2⃣При таком предположении, для какого-то дивана с несчастливыми людьми X и Y, мы либо заменяем Y на партнера X, либо заменяем X на партнера Y. Для каждой из двух возможностей мы можем попробовать оба варианта, используя подход с возвратом.

3⃣Для каждого дивана с двумя возможностями (т.е. оба человека на диване несчастливы) мы попробуем первый вариант, найдем ответ как ans1, затем отменим наш ход и попробуем второй вариант, найдем связанный ответ как ans2, отменим наш ход и затем вернем наименьший ответ.

😎 Решение:
class Solution:
def minSwapsCouples(self, row: List[int]) -> int:
self.N = len(row) // 2
self.pairs = [[0, 0] for _ in range(self.N)]
for i in range(self.N):
self.pairs[i][0] = row[2 * i] // 2
self.pairs[i][1] = row[2 * i + 1] // 2
return self.solve(0)

def swap(self, a: int, b: int, c: int, d: int):
self.pairs[a][b], self.pairs[c][d] = self.pairs[c][d], self.pairs[a][b]

def solve(self, i: int) -> int:
if i == self.N:
return 0
x, y = self.pairs[i]
if x == y:
return self.solve(i + 1)

jx, kx, jy, ky = 0, 0, 0, 0
for j in range(i + 1, self.N):
for k in range(2):
if self.pairs[j][k] == x:
jx, kx = j, k
if self.pairs[j][k] == y:
jy, ky = j, k

self.swap(i, 1, jx, kx)
ans1 = 1 + self.solve(i + 1)
self.swap(i, 1, jx, kx)

self.swap(i, 0, jy, ky)
ans2 = 1 + self.solve(i + 1)
self.swap(i, 0, jy, ky)

return min(ans1, ans2)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
#easy
Задача: 766. Toeplitz Matrix

Дана матрица размером m x n. Вернуть true, если матрица является Тёплицевой. В противном случае вернуть false.

Матрица является Тёплицевой, если все диагонали, идущие от верхнего левого к нижнему правому углу, содержат одинаковые элементы.

Пример:
Input: matrix = [[1,2,3,4],[5,1,2,3],[9,5,1,2]]
Output: true
Explanation:
In the above grid, the diagonals are:
"[9]", "[5, 5]", "[1, 1, 1]", "[2, 2, 2]", "[3, 3]", "[4]".
In each diagonal all elements are the same, so the answer is True.


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

1⃣Что отличает две координаты (r1, c1) и (r2, c2) на одной диагонали? Оказывается, две координаты находятся на одной диагонали тогда и только тогда, когда r1 - c1 == r2 - c2.м

2⃣Это приводит к следующей идее: запоминайте значение этой диагонали как groups[r - c]. Если обнаружено несоответствие, то матрица не является Тёплицевой; в противном случае, она является таковой.

3⃣Таким образом, для каждой ячейки матрицы сохраняйте значение диагонали в словаре groups с ключом r - c. Проходите по всем ячейкам матрицы и проверяйте, совпадает ли текущее значение с сохранённым в groups. Если где-то обнаруживается несоответствие, верните false. Если все элементы соответствуют, верните true.

😎 Решение:
class Solution:
def isToeplitzMatrix(self, matrix: List[List[int]]) -> bool:
groups = {}
for r in range(len(matrix)):
for c in range(len(matrix[0])):
if (r - c) not in groups:
groups[r - c] = matrix[r][c]
elif groups[r - c] != matrix[r][c]:
return False
return True


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
Forwarded from easyoffer
Ищу работу пол года

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

Честно говоря, искать работу полгода — это нонсенс. Очевидно, что человек делает что-то не так. Главная ошибка, которую совершают многие, — это создание иллюзии поиска работы.

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

Просматривает вакансии перед откликом.
Пытается понять, подходит ли он под вакансию. Если считает, что не подходит — не откликается.
Пишет сопроводительные письма (иногда даже уникальные под каждую вакансию).
Заполняет анкеты, проходит тесты.

Все эти действия отнимают время, но не приводят к результату.

Почему это не работает?

HR-менеджер не может вручную отсмотреть 2000 откликов, оценить каждое резюме и прочитать сопроводительные письма. Поэтому компании используют ATS-системы (системы автоматического подбора), которые анализируют резюме и определяют процент его соответствия вакансии.

Что делать, чтобы повысить шансы?

1️⃣ Добавить ключевые навыки в резюме — и в основной текст, и в теги. Возьмите их с easyoffer.ru

2️⃣ Убрать нерелевантный опыт, оставить только подходящий.

3️⃣ Оформить опыт так, чтобы он выглядел релевантным. Если у вас его нет, укажите проекты, стажировки или другой опыт, который можно представить как работу от 1 года. Если опыт слишком большой, сузьте его до 6 лет.

4️⃣ Откликаться на все вакансии без разбору. Если вы Junior, не ищите только стажер или Junior-вакансии — пробуйте везде. Не отказывайте себе сами, пусть это решит HR

5️⃣ Сделать резюме публичным, потому что HR-менеджеры часто ищут кандидатов не только среди откликов, но и в базе резюме.

6️⃣ Используйте ИИ по минимуму – ATS-системы считывают это и помечают "сгенерировано ИИ"

‼️ Главное правило: чем больше откликов — тем выше шанс получить оффер. Делайте резюме удобным для ATS-систем, и вас заметят.

1. Посмотрите видео о том как я вывел свою резюме в Топ1 на HH
2. Посмотрите видео как я нашел первую работу
3. Прочитайте этот кейс про оптимизацию резюме

Если прям вообще тяжело.

Создайте несколько разных резюме. Создайте 2, 3 да хоть 10 резюме. Настройте авто-отлики и ждите приглашения на собесы.

Не нужно создавать иллюзию поиска работы, сделайте несколько простых и актуальных действий.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41🤔1
#medium
Задача: 712. Minimum ASCII Delete Sum for Two Strings

Если даны две строки s1 и s2, верните наименьшую ASCII-сумму удаленных символов, чтобы сделать две строки равными.

Пример:
Input: s1 = "sea", s2 = "eat"
Output: 231


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

1⃣Создайте двумерный массив dp размером (len(s1) + 1) x (len(s2) + 1), где dp[i][j] будет хранить наименьшую ASCII-сумму удаленных символов для первых i символов s1 и первых j символов s2.

2⃣Заполните первую строку и первый столбец массива dp суммами ASCII значений символов, которые необходимо удалить для достижения пустой строки.

3⃣Заполните оставшуюся часть массива dp следующим образом: Если символы s1[i-1] и s2[j-1] равны, dp[i][j] = dp[i-1][j-1]. Иначе, dp[i][j] = min(dp[i-1][j] + ord(s1[i-1]), dp[i][j-1] + ord(s2[j-1])).

😎 Решение:
def minimumDeleteSum(s1, s2):
dp = [[0] * (len(s2) + 1) for _ in range(len(s1) + 1)]
for i in range(1, len(s1) + 1):
dp[i][0] = dp[i - 1][0] + ord(s1[i - 1])
for j in range(1, len(s2) + 1):
dp[0][j] = dp[0][j - 1] + ord(s2[j - 1])
for i in range(1, len(s1) + 1):
for j in range(1, len(s2) + 1):
if s1[i - 1] == s2[j - 1]:
dp[i][j] = dp[i - 1][j - 1]
else:
dp[i][j] = min(dp[i - 1][j] + ord(s1[i - 1]), dp[i][j - 1] + ord(s2[j - 1]))
return dp[-1][-1]


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1
#medium
Задача: 767. Reorganize String

Дана строка s, переставьте символы строки s так, чтобы любые два соседних символа не были одинаковыми.

Верните любую возможную перестановку строки s или верните "", если это невозможно.

Пример:
Input: s = "aab"
Output: "aba"


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

1⃣Инициализируйте пустой список ans для хранения переставленных символов. Создайте приоритетную очередь pq, используя структуру данных кучи. Каждый элемент в pq — это кортеж, содержащий количество символов и сам символ. Приоритетная очередь упорядочена так, что элементы с большим количеством имеют более высокий приоритет.

2⃣Извлеките элемент с наивысшим приоритетом из pq. Присвойте его количество и символ переменным count_first и char_first соответственно. Если ans пуст или текущий символ char_first отличается от последнего символа в ans, добавьте char_first в ans. Если количество char_first не равно нулю, уменьшите его на один. Если обновленное количество больше нуля, поместите его обратно в pq. Перейдите к следующей итерации.

3⃣В противном случае, если char_first совпадает с последним символом в ans, нужно выбрать другой символ. Если pq пуста, верните пустую строку, так как переставить символы невозможно. Извлеките следующий элемент из pq, присвоив его количество и символ переменным count_second и char_second соответственно. Добавьте char_second в ans. Если количество char_second не равно нулю, уменьшите его на один. Если обновленное количество больше нуля, поместите его обратно в pq. Наконец, поместите оригинальный char_first обратно в pq. Верните переставленные символы как строку, объединив элементы в ans.

😎 Решение:
import heapq

class Solution:
def reorganizeString(self, s: str) -> str:
charCounts = [0] * 26
for c in s:
charCounts[ord(c) - ord('a')] += 1

pq = []
for i in range(26):
if charCounts[i] > 0:
heapq.heappush(pq, (-charCounts[i], chr(i + ord('a'))))

result = []
while pq:
first = heapq.heappop(pq)
if not result or first[1] != result[-1]:
result.append(first[1])
if -first[0] > 1:
heapq.heappush(pq, (first[0] + 1, first[1]))
else:
if not pq:
return ""
second = heapq.heappop(pq)
result.append(second[1])
if -second[0] > 1:
heapq.heappush(pq, (second[0] + 1, second[1]))
heapq.heappush(pq, first)

return "".join(result)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
#medium
Задача: 713. Subarray Product Less Than K

Если задан массив целых чисел nums и целое число k, верните количество смежных подмассивов, в которых произведение всех элементов в подмассиве строго меньше k.

Пример:
Input: nums = [10,5,2,6], k = 100
Output: 8


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

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

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

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

😎 Решение:
def numSubarrayProductLessThanK(nums, k):
if k <= 1:
return 0
product = 1
count = 0
left = 0
for right in range(len(nums)):
product *= nums[right]
while product >= k:
product //= nums[left]
left += 1
count += right - left + 1
return count


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
#medium
Задача: 714. Best Time to Buy and Sell Stock with Transaction Fee

Вам дан массив prices, где prices[i] - это цена данной акции в i-й день, и целое число fee, представляющее собой комиссию за сделку. Найдите максимальную прибыль, которую вы можете получить. Вы можете совершить сколько угодно сделок, но за каждую сделку вам придется заплатить комиссию. Примечание: Вы не можете совершать несколько сделок одновременно (то есть вы должны продать акции, прежде чем купить их снова). Комиссия за сделку взимается только один раз за каждую покупку и продажу акций.

Пример:
Input: prices = [1,3,2,8,4,9], fee = 2
Output: 8


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

1⃣Инициализируйте две переменные: cash, представляющую максимальную прибыль без наличия акций, и hold, представляющую максимальную прибыль с наличием акций.

2⃣Пройдите по каждому элементу массива prices и обновите значения cash и hold, используя текущую цену и комиссию.

3⃣Верните значение cash, которое будет максимальной прибылью без наличия акций.

😎 Решение:
def maxProfit(prices, fee):
cash, hold = 0, -prices[0]
for price in prices:
cash = max(cash, hold + price - fee)
hold = max(hold, cash - price)
return cash


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
3
#medium
Задача: 771. Jewels and Stones

Вам даны строки jewels, представляющие типы камней, которые являются драгоценностями, и stones, представляющие камни, которые у вас есть. Каждый символ в stones является типом камня, который у вас есть. Вы хотите узнать, сколько из камней, которые у вас есть, также являются драгоценностями.

Буквы чувствительны к регистру, поэтому "a" считается другим типом камня, чем "A".

Пример:
Input: jewels = "aA", stones = "aAAbbbb"
Output: 3


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

1⃣Создайте множество из строки jewels для быстрой проверки, является ли камень драгоценностью. Это позволит эффективно проверять принадлежность каждого камня к драгоценностям.

2⃣Инициализируйте счетчик для подсчета количества камней, которые являются драгоценностями. Пройдите по каждому символу в строке stones и проверьте, содержится ли этот символ в множестве jewels.

3⃣Если символ содержится в множестве, увеличьте счетчик. В конце верните значение счетчика, которое будет количеством камней, являющихся драгоценностями.

😎 Решение:
class Solution:
def numJewelsInStones(self, J: str, S: str) -> int:
ans = 0
for s in S:
for j in J:
if j == s:
ans += 1
break
return ans


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2
#medium
Задача: 487. Max Consecutive Ones II

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

Пример:
Input: nums = [1,0,1,1,0]
Output: 4
Explanation:
- If we flip the first zero, nums becomes [1,1,1,1,0] and we have 4 consecutive ones.
- If we flip the second zero, nums becomes [1,0,1,1,1] and we have 3 consecutive ones.
The max number of consecutive ones is 4.


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

1⃣Для каждого возможного начала последовательности в массиве nums начните считать количество нулей.

2⃣Для каждой последовательности проверяйте, сколько нулей содержится в ней. Если количество нулей не превышает одного, обновите максимальную длину последовательности единиц.

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

😎 Решение:
class Solution:
def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
longestSequence = 0
for left in range(len(nums)):
numZeroes = 0
for right in range(left, len(nums)):
if nums[right] == 0:
numZeroes += 1
if numZeroes <= 1:
longestSequence = max(longestSequence, right - left + 1)
return longestSequence


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2
#medium
Задача: 772. Basic Calculator III

Реализуйте базовый калькулятор для вычисления простого строкового выражения.

Строка выражения содержит только неотрицательные целые числа, операторы '+', '-', '*', '/' и открывающие '(' и закрывающие скобки ')'. Целочисленное деление должно округляться к нулю.

Предполагается, что данное выражение всегда корректно. Все промежуточные результаты будут находиться в диапазоне [-2^31, 2^31 - 1].

Примечание: нельзя использовать встроенные функции для вычисления строк как математических выражений, такие как eval().

Пример:
Input: s = "1+1"
Output: 2


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

1⃣Определите вспомогательную функцию evaluate, которая принимает оператор и числовые аргументы. Заметьте, что эта функция идентична той, что представлена в подходе "Basic Calculator II". Инициализируйте несколько переменных: стек для хранения промежуточных результатов, curr для отслеживания текущего числа, которое мы строим, и previousOperator для отслеживания предыдущего оператора. Добавьте в строку s случайный символ, который не будет появляться во входных данных, например "@".

2⃣Итерация по входным данным. Для каждого символа c: если c является цифрой, добавьте его к curr. В противном случае, если c == '(', мы начинаем вычисление нового изолированного выражения. В этом случае сохраните previousOperator в стек и установите previousOperator = "+".

3⃣Если c является оператором, то необходимо вычислить значение curr. Используйте функцию evaluate, чтобы применить previousOperator к curr, и добавьте результат в стек. Затем сбросьте curr до нуля и обновите previousOperator = c. Если c == ')', это означает, что мы находимся в конце изолированного выражения и должны полностью его вычислить. Извлекайте из стека до тех пор, пока не достигнете оператора, суммируя все извлеченные числа в curr. Как только достигнете оператора, обновите previousOperator = stack.pop(). Верните сумму всех чисел в стеке.

😎 Решение:
class Solution:
def evaluate(self, operator, first, second):
x = int(first)
y = int(second)
if operator == '+':
return str(x)
elif operator == '-':
return str(-x)
elif operator == '*':
return str(x * y)
else:
return str(x // y)

def calculate(self, s: str) -> int:
stack = []
curr = ""
previousOperator = '+'
s += "@"
operators = set("+-*/")

for c in s:
if c.isdigit():
curr += c
elif c == '(':
stack.append(previousOperator)
previousOperator = '+'
else:
if previousOperator in "*/":
stack.append(self.evaluate(previousOperator, stack.pop(), curr))
else:
stack.append(self.evaluate(previousOperator, curr, "0"))

curr = ""
previousOperator = c
if c == ')':
currentTerm = 0
while stack[-1] not in operators:
currentTerm += int(stack.pop())
curr = str(currentTerm)
previousOperator = stack.pop()

return sum(int(num) for num in stack)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2
#hard
Задача: 715. Range Module

Модуль Range - это модуль, который отслеживает диапазоны чисел. Создайте структуру данных для отслеживания диапазонов, представленных в виде полуоткрытых интервалов, и запросов к ним. Полуоткрытый интервал [left, right) обозначает все вещественные числа x, где left <= x < right. Реализуйте класс RangeModule: RangeModule() Инициализирует объект структуры данных. void addRange(int left, int right) Добавляет полуоткрытый интервал [left, right), отслеживая каждое вещественное число в этом интервале. Добавление интервала, который частично перекрывает отслеживаемые в данный момент числа, должно добавить все числа в интервале [left, right), которые еще не отслеживаются. boolean queryRange(int left, int right) Возвращает true, если каждое действительное число в интервале [left, right) отслеживается в данный момент, и false в противном случае. void removeRange(int left, int right) Прекращает отслеживание каждого действительного числа, отслеживаемого в данный момент в полуоткрытом интервале [left, right).

Пример:
Input: prices = [1,3,2,8,4,9], fee = 2
Output: 8


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

1⃣Инициализируйте класс RangeModule с пустым списком диапазонов.

2⃣Для метода addRange(left, right) добавьте новый диапазон, объединяя его с существующими перекрывающимися диапазонами. Для метода queryRange(left, right) проверьте, полностью ли данный диапазон содержится в отслеживаемых диапазонах.

3⃣Для метода removeRange(left, right) удалите указанный диапазон, разбивая существующие диапазоны на соответствующие части.

😎 Решение:
class RangeModule:

def __init__(self):
self.ranges = []

def addRange(self, left, right):
new_ranges = []
i = 0
while i < len(self.ranges) and self.ranges[i][1] < left:
new_ranges.append(self.ranges[i])
i += 1
while i < len(self.ranges) and self.ranges[i][0] <= right:
left = min(left, self.ranges[i][0])
right = max(right, self.ranges[i][1])
i += 1
new_ranges.append((left, right))
while i < len(self.ranges):
new_ranges.append(self.ranges[i])
i += 1
self.ranges = new_ranges

def queryRange(self, left, right):
for l, r in self.ranges:
if l <= left and right <= r:
return True
return False

def removeRange(self, left, right):
new_ranges = []
for l, r in self.ranges:
if l < left:
new_ranges.append((l, min(r, left)))
if right < r:
new_ranges.append((max(l, right), r))
self.ranges = new_ranges


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21
#hard
Задача: 774. Minimize Max Distance to Gas Station

Вам дан массив целых чисел stations, который представляет позиции автозаправочных станций на оси x. Вам также дано целое число k.

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

Определим penalty() как максимальное расстояние между соседними автозаправочными станциями после добавления k новых станций.

Верните наименьшее возможное значение penalty(). Ответы, отличающиеся от фактического ответа не более чем на 10^-6, будут приняты.

Пример:
Input: stations = [1,2,3,4,5,6,7,8,9,10], k = 9
Output: 0.50000


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

1⃣Пусть i-й интервал равен deltas[i] = stations[i+1] - stations[i]. Мы хотим найти dp[n+1][k] как рекурсию. Мы можем поставить x автозаправочных станций в интервал n+1 с наилучшим расстоянием deltas[n+1] / (x+1), затем оставшиеся интервалы можно решить с ответом dp[n][k-x]. Ответ — это минимум среди всех x.

2⃣Из этой рекурсии мы можем разработать решение с использованием динамического программирования. Инициализируем двумерный массив dp, где dp[i][j] будет хранить минимальное возможное значение penalty при добавлении j автозаправочных станций на первые i интервалов.

3⃣Заполняем dp таблицу начиная с базового случая, когда нет добавленных станций. Затем для каждого интервала и количества добавленных станций вычисляем минимальное значение penalty, используя вышеописанную рекурсию. Итоговый ответ будет находиться в dp[n][k], где n — количество интервалов, а k — количество добавляемых станций.

😎 Решение:
class Solution:
def minmaxGasDist(self, stations: List[int], K: int) -> float:
N = len(stations)
deltas = [0] * (N-1)
for i in range(N-1):
deltas[i] = stations[i+1] - stations[i]

dp = [[0] * (K+1) for _ in range(N-1)]
for i in range(K+1):
dp[0][i] = deltas[0] / (i+1)

for p in range(1, N-1):
for k in range(K+1):
bns = float('inf')
for x in range(k+1):
bns = min(bns, max(deltas[p] / (x+1), dp[p-1][k-x]))
dp[p][k] = bns

return dp[N-2][K]


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1
#medium
Задача: 775. Global and Local Inversions

Дан массив целых чисел nums длиной n, который представляет собой перестановку всех чисел в диапазоне [0, n - 1].

Число глобальных инверсий — это количество различных пар (i, j), где:

0 <= i < j < n
nums[i] > nums[j]
Число локальных инверсий — это количество индексов i, где:

0 <= i < n - 1
nums[i] > nums[i + 1]
Верните true, если количество глобальных инверсий равно количеству локальных инверсий.

Пример:
Input: nums = [1,0,2]
Output: true
Explanation: There is 1 global inversion and 1 local inversion.


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

1⃣Локальная инверсия также является глобальной инверсией. Таким образом, нам нужно проверить, есть ли в нашей перестановке какие-либо нелокальные инверсии (A[i] > A[j], i < j) с j - i > 1.

2⃣Для этого мы можем перебрать каждый индекс i и проверить, есть ли индекс j, такой что j > i + 1 и nums[i] > nums[j]. Если такой индекс найден, это будет означать наличие нелокальной инверсии.

3⃣Если для всех индексов i условие выше не выполняется, это значит, что количество глобальных инверсий равно количеству локальных инверсий, и мы возвращаем true. В противном случае, если хотя бы одна нелокальная инверсия найдена, мы возвращаем false.

😎 Решение:
class Solution:
def isIdealPermutation(self, A: List[int]) -> bool:
N = len(A)
for i in range(N):
for j in range(i + 2, N):
if A[i] > A[j]:
return False
return True


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