es
Feedback
Swift | LeetCode

Swift | LeetCode

Ir al canal en Telegram

Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @easyoffer_adv

Mostrar más
1 349
Suscriptores
-224 horas
-47 días
-1630 días
Atraer Suscriptores
julio '26
julio '260
en 0 canales
junio '26
+4
en 0 canales
Get PRO
mayo '26
+4
en 0 canales
Get PRO
abril '26
+6
en 0 canales
Get PRO
marzo '26
+4
en 0 canales
Get PRO
febrero '26
+9
en 0 canales
Get PRO
enero '26
+17
en 0 canales
Get PRO
diciembre '25
+12
en 0 canales
Get PRO
noviembre '25
+54
en 0 canales
Get PRO
octubre '25
+30
en 0 canales
Get PRO
septiembre '25
+32
en 0 canales
Get PRO
agosto '25
+37
en 0 canales
Get PRO
julio '25
+34
en 1 canales
Get PRO
junio '25
+30
en 0 canales
Get PRO
mayo '25
+33
en 0 canales
Get PRO
abril '25
+68
en 0 canales
Get PRO
marzo '25
+143
en 2 canales
Get PRO
febrero '25
+113
en 1 canales
Get PRO
enero '25
+113
en 53 canales
Get PRO
diciembre '24
+50
en 0 canales
Get PRO
noviembre '24
+55
en 0 canales
Get PRO
octubre '24
+143
en 12 canales
Get PRO
septiembre '24
+459
en 331 canales
Get PRO
agosto '24
+87
en 0 canales
Get PRO
julio '24
+325
en 219 canales
Get PRO
junio '24
+261
en 232 canales
Fecha
Crecimiento de Suscriptores
Menciones
Canales
01 julio0
Publicaciones del Canal
Задача: 1372. Longest ZigZag Path in a Binary Tree Сложность: medium Вам дан корень бинарного дерева. Зигзагообразный путь для бинарного дерева определяется следующим образом: Выберите любой узел в бинарном дереве и направление (вправо или влево). Если текущее направление вправо, перейдите к правому дочернему узлу текущего узла; иначе перейдите к левому дочернему узлу. Измените направление с вправо на влево или с влево на вправо. Повторяйте второй и третий шаги, пока не сможете двигаться по дереву. Длина зигзагообразного пути определяется как количество посещенных узлов минус 1 (один узел имеет длину 0). Верните длину самого длинного зигзагообразного пути, содержащегося в этом дереве. Пример:
Input: s = "rat"
Output: "art"
Explanation: The word "rat" becomes "art" after re-ordering it with the mentioned algorithm.
👨‍💻 Алгоритм: 1⃣Рекурсивная функция DFS: Создайте рекурсивную функцию dfs, которая будет выполнять обход дерева и отслеживать текущую длину зигзагообразного пути и направление движения (влево или вправо). 2⃣Обновление максимальной длины пути: При каждом вызове рекурсивной функции обновляйте максимальную длину зигзагообразного пути, если текущая длина больше текущего максимума. 3⃣Рекурсивный вызов для левого и правого дочерних узлов: Рекурсивно вызывайте функцию dfs для левого и правого дочерних узлов с обновленными параметрами длины и направления. 😎 Решение:
class TreeNode {
    var val: Int
    var left: TreeNode?
    var right: TreeNode?
    init(_ val: Int) { self.val = val; self.left = nil; self.right = nil }
}

class Solution {
    var maxLength = 0

    func longestZigZag(_ root: TreeNode?) -> Int {
        dfs(root, true, 0)
        dfs(root, false, 0)
        return maxLength
    }

    func dfs(_ node: TreeNode?, _ isLeft: Bool, _ length: Int) {
        guard let node = node else { return }
        maxLength = max(maxLength, length)
        if isLeft {
            dfs(node.left, false, length + 1)
            dfs(node.right, true, 1)
        } else {
            dfs(node.right, true, length + 1)
            dfs(node.left, false, 1)
        }
    }
}
Ставь 👍 и забирай 📚 Базу знаний

2
Задача: 287. Find the Duplicate Number Сложность: medium Дан массив целых чисел nums, содержащий n + 1 целых чисел, где каждое число находится в диапазоне [1, n] включительно. В массиве есть только одно повторяющееся число, верните это повторяющееся число. Вы должны решить задачу, не изменяя массив nums и используя только постоянное дополнительное пространство. Пример: Input: nums = [1,3,4,2,2] Output: 2 👨‍💻 Алгоритм: 1⃣Определение дубликата: Итерируйте по массиву, оценивая каждый элемент (назовем его cur). Используйте абсолютное значение текущего элемента, чтобы получить индекс. Если элемент по индексу cur отрицательный, значит, мы уже встречали этот элемент ранее, и cur является дубликатом. Сохраните cur как дубликат и выйдите из цикла. Если элемент по индексу cur положительный, инвертируйте знак этого элемента, чтобы пометить его как встреченный, и перейдите к следующему элементу. 2⃣Восстановление массива: Пройдите по массиву и измените все отрицательные элементы обратно на положительные, чтобы восстановить исходное состояние массива. 3⃣Возврат результата: Верните найденный дубликат. 😎 Решение: class Solution { func findDuplicate(_ nums: [Int]) -> Int { var nums = nums var duplicate = -1 for i in 0..<nums.count { let cur = abs(nums[i]) if nums[cur] < 0 { duplicate = cur break } nums[cur] *= -1 } for i in 0..<nums.count { nums[i] = abs(nums[i]) } return duplicate } } Ставь 👍 и забирай 📚 Базу знаний
49
3
Задача: 245. Shortest Word Distance II Сложность: medium Дан массив строк wordsDict и две строки word1 и word2, которые уже существуют в массиве. Верните наименьшее расстояние между вхождениями этих двух слов в списке. Обратите внимание, что word1 и word2 могут быть одинаковыми. Гарантируется, что они представляют собой два отдельных слова в списке. Пример: Input: wordsDict = ["practice", "makes", "perfect", "coding", "makes"], word1 = "makes", word2 = "coding" Output: 1 👨‍💻 Алгоритм: 1⃣Переберите список wordsDict и сохраните индексы слова word1 в список indices1 и индексы слова word2 в список indices2. Инициализируйте переменную shortestDistance = INT_MAX. 2⃣Переберите индексы в списке indices1 и для каждого индекса найдите верхнюю границу в списке indices2, используя бинарный поиск, и сохраните этот индекс в переменную x. Рассмотрите индексы indices2[x] и indices2[x - 1], обновляя shortestDistance, если индексы не совпадают. 3⃣Верните значение переменной shortestDistance. 😎 Решение: class Solution { func shortestWordDistance(_ wordsDict: [String], _ word1: String, _ word2: String) -> Int { var indices1 = [Int]() var indices2 = [Int]() for (i, word) in wordsDict.enumerated() { if word == word1 { indices1.append(i) } if word == word2 { indices2.append(i) } } var shortestDistance = Int.max for index in indices1 { let x = indices2.partitioningIndex(where: { $0 > index }) if x < indices2.count { shortestDistance = min(shortestDistance, indices2[x] - index) } if x > 0 && indices2[x - 1] != index { shortestDistance = min(shortestDistance, index - indices2[x - 1]) } } return shortestDistance } } Ставь 👍 и забирай 📚 Базу знаний
61
4
Задача: 117. Populating Next Right Pointers in Each Node II Сложность: medium Вам дано бинарное дерево: struct Node { int val; Node *left; Node *right; Node *next; } Заполните каждый указатель next, чтобы он указывал на следующий правый узел. Если следующего правого узла нет, указатель next должен быть установлен в NULL. Изначально все указатели next установлены в NULL. Пример: Input: root = [1,2,3,4,5,null,7] Output: [1,#,2,3,#,4,5,7,#] Explanation: Given the above 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 Foundation class Node { var value: Int var left: Node? var right: Node? var next: Node? init(_ value: Int) { self.value = value } } class Solution { func connect(_ root: Node?) -> Node? { guard let root = root else { return nil } var queue: [Node] = [root] while !queue.isEmpty { let size = queue.count for i in 0..<size { let node = queue.removeFirst() if i < size - 1 { node.next = queue.first } if let leftChild = node.left { queue.append(leftChild) } if let rightChild = node.right { queue.append(rightChild) } } } return root } } Ставь 👍 и забирай 📚 Базу знаний
72
5
Задача: 1231. Divide Chocolate Сложность: hard У вас есть одна шоколадка, состоящая из нескольких кусочков. Каждый кусочек имеет свою сладость, заданную массивом сладости. Вы хотите поделиться шоколадом со своими k друзьями, поэтому начинаете разрезать шоколадку на k + 1 кусочков с помощью k разрезов, каждый кусочек состоит из нескольких последовательных кусочков. Будучи щедрым, вы съедите кусочек с минимальной общей сладостью, а остальные кусочки отдадите своим друзьям. Найдите максимальную общую сладость кусочка, который вы можете получить, оптимально разрезав шоколадку. Пример: Input: sweetness = [1,2,3,4,5,6,7,8,9], k = 5 Output: 6 👨‍💻 Алгоритм: 1⃣Для решения задачи мы можем использовать метод двоичного поиска для определения максимальной минимальной сладости, которую можно получить. 2⃣Двоичный поиск: Мы будем искать ответ в диапазоне от минимальной сладости до суммы всех сладостей. Начнем с середины этого диапазона и проверим, можно ли разрезать шоколад таким образом, чтобы минимальная сладость была не менее этого значения. 3⃣Проверка делимости: Для каждой попытки значения сладости в двоичном поиске проверим, можем ли мы разрезать шоколад так, чтобы каждая из k+1 частей имела сладость не меньше текущего значения. 😎 Решение: class Solution { func maximizeSweetness(_ sweetness: [Int], _ k: Int) -> Int { func canDivide(_ minSweetness: Int) -> Bool { var currentSum = 0 var cuts = 0 for sweet in sweetness { currentSum += sweet if currentSum >= minSweetness { cuts += 1 currentSum = 0 } } return cuts >= k + 1 } var left = sweetness.min()! var right = sweetness.reduce(0, +) / (k + 1) while left < right { let mid = (left + right + 1) / 2 if canDivide(mid) { left = mid } else { right = mid - 1 } } return left } } Ставь 👍 и забирай 📚 Базу знаний
83
6
Задача: 174. Dungeon Game Сложность: hard Демоны поймали принцессу и заперли её в самой нижней правой комнате подземелья. Подземелье состоит из комнат, расположенных в форме сетки размером m x n. Наш отважный рыцарь изначально находится в комнате в верхнем левом углу и должен пробиться через подземелье, чтобы спасти принцессу. Рыцарь имеет начальный запас здоровья, представленный положительным целым числом. Если в какой-то момент его уровень здоровья упадет до 0 или ниже, он умирает мгновенно. Некоторые комнаты охраняются демонами (представлены отрицательными числами), так что рыцарь теряет здоровье, входя в эти комнаты; другие комнаты либо пусты (обозначены как 0), либо содержат магические сферы, которые увеличивают здоровье рыцаря (представлены положительными числами). Чтобы как можно скорее добраться до принцессы, рыцарь решает двигаться только вправо или вниз на каждом шаге. Верните минимальное начальное здоровье рыцаря, необходимое для того, чтобы он мог спасти принцессу. Обратите внимание, что любая комната может содержать угрозы или усилители, даже первая комната, в которую входит рыцарь, и нижняя правая комната, где заключена принцесса. Пример: Input: dungeon = [[-2,-3,3],[-5,-10,1],[10,30,-5]] Output: 7 Explanation: The initial health of the knight must be at least 7 if he follows the optimal path: RIGHT-> RIGHT -> DOWN -> DOWN. 👨‍💻 Алгоритм: 1⃣Определение матрицы dp: Создайте матрицу dp размером с подземелье, где элемент dp[row][col] указывает минимальное количество здоровья, необходимое рыцарю, чтобы начать путь из ячейки dungeon[row][col] и достигнуть цели (нижней правой ячейки). 2⃣Инициализация и заполнение dp: Начните с правого нижнего угла подземелья и идите в обратном направлении — справа налево и снизу вверх. Для каждой ячейки вычислите соответствующее значение в dp: Если возможно, шаг вправо из текущей ячейки подземелья требует right_health здоровья. Если возможно, шаг вниз из текущей ячейки подземелья требует down_health здоровья. Возьмите минимальное значение из right_health и down_health для dp[row][col]. Если ни один из вышеперечисленных вариантов не доступен (то есть вы находитесь в ячейке назначения), учитывайте два подслучая: Если в ячейке магический шар, достаточно 1 единицы здоровья. Если в ячейке демон, рыцарю необходимо иметь единицу здоровья плюс урон, который может нанести демон. 3⃣Результат вычислений: Значение в dp[0][0] будет указывать на минимальное количество здоровья, необходимое рыцарю, чтобы начать свой путь из верхней левой ячейки подземелья и успешно спасти принцессу, учитывая все угрозы на его пути. 😎 Решение: func calculateMinimumHP(dungeon: [[Int]]) -> Int { let rows = dungeon.count let cols = dungeon[0].count var dp = Array(repeating: Array(repeating: Int.max, count: cols), count: rows) func getMinHealth(currCell: Int, nextRow: Int, nextCol: Int) -> Int { guard nextRow < rows, nextCol < cols else { return Int.max } let nextCell = dp[nextRow][nextCol] return max(1, nextCell - currCell) } for row in stride(from: rows - 1, through: 0, by: -1) { for col in stride(from: cols - 1, through: 0, by: -1) { let currCell = dungeon[row][col] let rightHealth = getMinHealth(currCell: currCell, nextRow: row, nextCol: col + 1) let downHealth = getMinHealth(currCell: currCell, nextRow: row + 1, nextCol: col) let nextHealth = min(rightHealth, downHealth) let minHealth = nextHealth != Int.max ? nextHealth : (currCell >= 0 ? 1 : 1 - currCell) dp[row][col] = minHealth } } return dp[0][0] } Ставь 👍 и забирай 📚 Базу знаний
77
7
Задача: 604. Design Compressed String Iterator Сложность: easy Разработайте и реализуйте структуру данных для итератора сжатой строки. Данная сжатая строка будет в виде каждой буквы, за которой следует положительное целое число, представляющее количество этой буквы в оригинальной несжатой строке. Реализуйте класс StringIterator: - next(): Возвращает следующий символ, если в оригинальной строке еще остались несжатые символы, в противном случае возвращает пробел. - hasNext(): Возвращает true, если в оригинальной строке остались символы, которые нужно распаковать, в противном случае возвращает false. Пример: Input ["StringIterator", "next", "next", "next", "next", "next", "next", "hasNext", "next", "hasNext"] [["L1e2t1C1o1d1e1"], [], [], [], [], [], [], [], [], []] Output [null, "L", "e", "e", "t", "C", "o", true, "d", true] Explanation StringIterator stringIterator = new StringIterator("L1e2t1C1o1d1e1"); stringIterator.next(); // return "L" stringIterator.next(); // return "e" stringIterator.next(); // return "e" stringIterator.next(); // return "t" stringIterator.next(); // return "C" stringIterator.next(); // return "o" stringIterator.hasNext(); // return True stringIterator.next(); // return "d" stringIterator.hasNext(); // return True 👨‍💻 Алгоритм: 1⃣Предварительная обработка Мы заранее создаем несжатую строку. Для этого проходим по данному сжатому строковому представлению и добавляем несжатые буквы для каждой сжатой буквы в результирующий строковый строитель res. Чтобы найти количество несжатых букв, мы проходим по данному сжатому строковому представлению. Когда находим букву, определяем следующее за ней число, используя десятичную арифметику. Таким образом, получаем два элемента (букву и количество), необходимые для формирования текущего фрагмента несжатой строки. 2⃣Операция next() Начинаем с проверки, есть ли еще несжатые буквы в строке. Если нет, hasNext() возвращает False, а next() возвращает пробел (' '). В противном случае возвращаем букву, на которую указывает ptr, указывающий на следующую букву для возврата. Перед возвратом буквы также обновляем ptr, чтобы указывать на следующую букву в res. 3⃣Операция hasNext() Если указатель ptr выходит за пределы массива res, это указывает на то, что больше несжатых букв нет. В этом случае возвращаем False. В противном случае возвращаем True. 😎 Решение: class StringIterator { var res = [Character]() var ptr = 0 init(_ s: String) { var i = s.startIndex while i < s.endIndex { let ch = s[i] i = s.index(after: i) var num = 0 while i < s.endIndex, let digit = s[i].wholeNumberValue { num = num * 10 + digit i = s.index(after: i) } res.append(contentsOf: repeatElement(ch, count: num)) } } func next() -> Character { guard hasNext() else { return " " } let char = res[ptr] ptr += 1 return char } func hasNext() -> Bool { return ptr < res.count } } Ставь 👍 и забирай 📚 Базу знаний
78
8
Задача: 763. Partition Labels Сложность: medium Вам дана строка s. Мы хотим разбить строку на как можно больше частей так, чтобы каждая буква встречалась не более чем в одной части. Обратите внимание, что разбиение выполняется так, чтобы после конкатенации всех частей по порядку получилась строка s. Верните список целых чисел, представляющих размер этих частей. Пример: Input: s = "ababcbacadefegdehijhklij" Output: [9,7,8] 👨‍💻 Алгоритм: 1⃣Создайте словарь для хранения последней позиции каждой буквы в строке. 2⃣Пройдите по строке, отслеживая максимальную позицию текущей части. 3⃣Когда текущая позиция совпадает с максимальной позицией, завершите часть и начните новую. 😎 Решение: func partitionLabels(_ s: String) -> [Int] { var lastPos = [Character: Int]() for (idx, char) in s.enumerated() { lastPos[char] = idx } var partitions = [Int]() var j = 0, anchor = 0 for (i, char) in s.enumerated() { j = max(j, lastPos[char]!) if i == j { partitions.append(i - anchor + 1) anchor = i + 1 } } return partitions } Ставь 👍 и забирай 📚 Базу знаний
74
9
Задача: 1539. Kth Missing Positive Number Сложность: easy Дан массив arr из положительных целых чисел, отсортированных в строго возрастающем порядке, и целое число k. Верните k-й положительный целочисленный элемент, который отсутствует в этом массиве. Пример: Input: arr = [2,3,4,7,11], k = 5 Output: 9 Explanation: The missing positive integers are [1,5,6,8,9,10,12,13,...]. The 5th missing positive integer is 9. 👨‍💻 Алгоритм: 1⃣Проверьте, является ли k-й отсутствующий номер меньше первого элемента массива. Если это так, верните k. Уменьшите k на количество положительных чисел, отсутствующих до начала массива: k -= arr[0] - 1. 2⃣Итерируйтесь по элементам массива. На каждом шаге вычисляйте количество отсутствующих положительных чисел между i+1-м и i-м элементами: currMissing = arr[i + 1] - arr[i] - 1. Сравните k с currMissing. Если k <= currMissing, то число для возврата находится между arr[i + 1] и arr[i], и вы можете его вернуть: arr[i] + k. В противном случае уменьшите k на currMissing и продолжайте. 3⃣Если элемент, который нужно вернуть, больше последнего элемента массива, верните его: arr[n - 1] + k. 😎 Решение class Solution { func findKthPositive(_ arr: [Int], _ k: Int) -> Int { var k = k if k <= arr[0] - 1 { return k } k -= arr[0] - 1 let n = arr.count for i in 0..<n - 1 { let currMissing = arr[i + 1] - arr[i] - 1 if k <= currMissing { return arr[i] + k } k -= currMissing } return arr[n - 1] + k } } Ставь 👍 и забирай 📚 Базу знаний
79
10
Осталось 3 часа до конца акции: «Пожизненный PRO тариф — по цене 1 года» Поиск работы отнимает силы, время и веру в себя, но
Осталось 3 часа до конца акции: «Пожизненный PRO тариф — по цене 1 года» Поиск работы отнимает силы, время и веру в себя, но не у тех кто использует easyoffer PRO. Успей сделать самую выгодную инвестицию в развитие своей карьеры. Акция закончится уже сегодня 23 июня 23:59 по мск: 👉 https://easyoffer.ru/pro
26
11
Задача: 1356. Sort Integers by The Number of 1 Bits Сложность: easy Дан целочисленный массив arr. Отсортируйте целые числа в массиве по возрастанию числа единиц в их двоичном представлении, а в случае, если у двух или более чисел одинаковое количество единиц, отсортируйте их по возрастанию. Верните массив после сортировки. Пример: Input: arr = [1024,512,256,128,64,32,16,8,4,2,1] Output: [1,2,4,8,16,32,64,128,256,512,1024] Explantion: All integers have 1 bit in the binary representation, you should just sort them in ascending order. 👨‍💻 Алгоритм: 1⃣Создание функции для подсчета единиц: Создайте функцию, которая принимает целое число и возвращает количество единиц в его двоичном представлении. 2⃣Сортировка массива: Используйте встроенную функцию сортировки, передавая ей пользовательскую функцию сравнения, которая использует количество единиц в двоичном представлении чисел для сортировки. Если количество единиц одинаковое, используйте само число для сортировки. 3⃣Возврат отсортированного массива: Верните отсортированный массив. 😎 Решение: class Solution { func sortByBits(_ arr: [Int]) -> [Int] { return arr.sorted { (a, b) -> Bool in let countA = a.nonzeroBitCount let countB = b.nonzeroBitCount return countA == countB ? a < b : countA < countB } } } Ставь 👍 и забирай 📚 Базу знаний
85
12
Задача: 128. Longest Consecutive Sequence Сложность: Medium Дан несортированный массив целых чисел nums. Верните длину самой длинной последовательности последовательных элементов. Необходимо написать алгоритм, который работает за время O(n). Пример: Input: nums = [100,4,200,1,3,2] Output: 4 Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4. 👨‍💻 Алгоритм: 1⃣Проверка базового случая: Перед началом работы проверяем базовый случай с пустым массивом. Самая длинная последовательность в пустом массиве, очевидно, равна 0, поэтому мы можем просто вернуть это значение. 2⃣Обработка чисел в массиве: Для всех других случаев мы сортируем массив nums и рассматриваем каждое число, начиная со второго (поскольку нам нужно сравнивать каждое число с предыдущим). Если текущее число и предыдущее равны, то текущая последовательность не удлиняется и не прерывается, поэтому мы просто переходим к следующему числу. Если числа не равны, то нужно проверить, удлиняет ли текущее число последовательность (т.е. nums[i] == nums[i-1] + 1). Если удлиняет, то мы увеличиваем наш текущий счёт и продолжаем. 3⃣Завершение обработки и возврат результата: В противном случае последовательность прерывается, и мы записываем нашу текущую последовательность и сбрасываем её до 1 (чтобы включить число, которое прервало последовательность). Возможно, что последний элемент массива nums является частью самой длинной последовательности, поэтому мы возвращаем максимум из текущей последовательности и самой длинной. 😎 Решение: func longestConsecutive(_ nums: [Int]) -> Int { var longestStreak = 0 let numSet = Set(nums) for num in numSet { if !numSet.contains(num - 1) { var currentNum = num var currentStreak = 1 while numSet.contains(currentNum + 1) { currentNum += 1 currentStreak += 1 } longestStreak = max(longestStreak, currentStreak) } } return longestStreak } Ставь 👍 и забирай 📚 Базу знаний
85
13
Последний день акции: «Пожизненный PRO тариф — по цене 1 года» 🚀 PRO включает: – Полный доступ ко всем грейдам и профессиям
Последний день акции: «Пожизненный PRO тариф — по цене 1 года» 🚀 PRO включает: – Полный доступ ко всем грейдам и профессиям – База live-coding задач и вопросов из технических собеседований с вероятностью их встречи – Примеры лучших ответов от Senior разработчиков – 1100+ записи реальных собеседований, в том числе в топовые компании (Сбер, Авито, Яндекс, WB, OZON, МТС и др.) – База 400+ тестовых заданий от компаний. – Автоотклики на вакансии в хедхантер – Аналитика ТОП-требований из вакансий для лучшего написания резюме и прохождения ATS систем рекрутеров – Генератор уникального резюме и CV под каждую вакансию – Тренажеры подготовки к собеседованию: «Реальное собеседование» и «Проработка вопросов» по методике интервальных повторений (как Anki) – (скоро) Агрегатор вакансий – (скоро) Сообщество Акция закончится уже сегодня 23 июня 23:59 по мск: 👉 https://easyoffer.ru/pro
58
14
Задача: 1295. Find Numbers with Even Number of Digits Сложность: easy Дан массив чисел nums. Верните количество чисел в массиве, которые содержат четное количество цифр. Пример: Input: nums = [12,345,2,6,7896] Output: 2 Explanation: 12 contains 2 digits (even number of digits). 345 contains 3 digits (odd number of digits). 2 contains 1 digit (odd number of digits). 6 contains 1 digit (odd number of digits). 7896 contains 4 digits (even number of digits). Therefore only 12 and 7896 contain an even number of digits. 👨‍💻 Алгоритм: 1⃣Определите вспомогательную функцию hasEvenDigits, которая принимает num в качестве входных данных и возвращает true, если количество цифр четное, иначе возвращает false. 2⃣Внутри функции hasEvenDigits. Инициализируйте переменную digitCount значением 0. Пока num не равно нулю: Увеличивайте digitCount на 1. Делите num на 10. Возвращайте digitCount & 1 == 0. 3⃣В функции findNumbers. Инициализируйте переменную evenDigitCount значением 0. Для каждого числа num в массиве nums, проверяйте, возвращает ли hasEvenDigits(num) значение true. Если да, увеличивайте evenDigitCount на 1. Возвращайте evenDigitCount. 😎 Решение: class Solution { func hasEvenDigits(_ num: Int) -> Bool { var digitCount = 0 var num = num while num > 0 { digitCount += 1 num /= 10 } return (digitCount & 1) == 0 } func findNumbers(_ nums: [Int]) -> Int { var evenDigitCount = 0 for num in nums { if hasEvenDigits(num) { evenDigitCount += 1 } } return evenDigitCount } } Ставь 👍 и забирай 📚 Базу знаний
78
15
Пожизненный PRO тариф — по цене 1 года. Покупаешь один раз — пользуешься всю жизнь: 👉 https://easyoffer.ru/pro 🚀 PRO-доступ
Пожизненный PRO тариф — по цене 1 года. Покупаешь один раз — пользуешься всю жизнь: 👉 https://easyoffer.ru/pro 🚀 PRO-доступ закроет 99% проблем на пути к офферу: 1. Полный доступ ко всем грейдам и профессиям. Не важно, Junior вы или Senior, Тестировщик, Разработчик, Проджект — вы получите материалы под ваш текущий уровень и цели, без ограничений. 2. База live-coding задач и вопросов с реальных собесов с уникальной системой вероятности их встречи. Вы будете готовиться не вслепую, а точечно по тем темам, которые спрашивают чаще всего. 3. Эталонные ответы от Senior-разработчиков. Никакой воды и догадок — только четкие, структурированные решения, за которые дают «зеленый свет» к офферу 4. 1100+ записей реальных собеседований (включая топы: Сбер, Авито, Яндекс, WB, OZON, МТС). Вы увидите всё изнутри: как спрашивают, как отвечают сильные кандидаты и на каких ошибках проваливаются 80% проходящих. 5. База 400+ тестовых заданий. Если вы еще студент, то практикуйтесь на решении задач, которые помогут попасть на собес 6. Автоотклики на Хедхантере — пока вы спите, ваше резюме летит к рекрутерам автоматически. Это экономия сотен часов ручного кликанья. 7. Аналитика ТОП-требований из вакансий. Мы парсим рынок и показываем, какие скиллы сейчас в цене. Это позволит вам точечно апгрейдить резюме и проходить суровые ATS-фильтры (которые отсеивают до 75% резюме еще до просмотра рекрутером). 8. Генератор уникального резюме и CV под каждую вакансию. Забудьте про «универсальное» резюме — нейросеть адаптирует ваш опыт под конкретную позицию за минуту, повышая шансы на приглашение в разы. 9. Тренажеры подготовки к собеседованию: «Реальное собеседование» — сценарий вопросов из реальных интервью «Проработка вопросов» — флеш карточки с вопросами/ответами по методике интервальных повторений (как Anki) 10. (Скоро) Агрегатор вакансий — все вакансии из HH, Telegram, LinkedIn и других площадок в одной ленте. 11. (Скоро) Закрытое комьюнити — нетворкинг и помощь в сложных вопросах от таких же целеустремленных айтишников. Завтра последний день акции: 👉 https://easyoffer.ru/pro
63
16
Задача: 1359. Count All Valid Pickup and Delivery Options Сложность: hard Дано n заказов, каждый из которых состоит из услуги забора и доставки. Посчитайте все возможные допустимые последовательности забора/доставки, такие что доставка(i) всегда идет после забора(i). Поскольку ответ может быть слишком большим, верните его по модулю 10^9 + 7. Пример: Input: n = 1 Output: 1 Explanation: Unique order (P1, D1), Delivery 1 always is after of Pickup 1. 👨‍💻 Алгоритм: 1⃣Инициализация: Используйте динамическое программирование для хранения количества допустимых последовательностей для каждого количества заказов от 1 до n. 2⃣Рекурсивное вычисление: Для каждого количества заказов k используйте рекурсивную формулу для вычисления количества допустимых последовательностей, учитывая, что каждая новая пара (забор и доставка) может быть вставлена в любую из существующих позиций. 3⃣Возвращение результата: Верните результат для n заказов, применяя модуль 10^9 + 7 для предотвращения переполнения. 😎 Решение: class Solution { func countOrders(_ n: Int) -> Int { let MOD = 1_000_000_007 var dp = [Int](repeating: 0, count: n + 1) dp[0] = 1 for i in 1...n { dp[i] = dp[i - 1] * (2 * i - 1) * i % MOD } return dp[n] } } Ставь 👍 и забирай 📚 Базу знаний
71
17
Задача: 96. Unique Binary Search Trees Сложность: medium Дано целое число n. Верните количество структурно уникальных деревьев бинарного поиска (BST), которые содержат ровно n узлов с уникальными значениями от 1 до n. Пример: Input: n = 3 Output: 5 👨‍💻 Алгоритм: 1⃣Задача состоит в том, чтобы рассчитать количество уникальных BST (бинарных деревьев поиска). Для этого мы можем определить две функции: G(n): количество уникальных BST для последовательности длины n. F(i, n): количество уникальных BST, где число i является корнем BST (1 ≤ i ≤ n). Как видно, G(n) - это именно та функция, которая нам нужна для решения задачи. 2⃣Позднее мы увидим, что G(n) можно вывести из F(i, n), которая, в свою очередь, рекурсивно относится к G(n). Следуя идее из раздела "Интуиция", мы видим, что общее количество уникальных BST G(n) равно сумме BST F(i, n) с перечислением каждого числа i (1 ≤ i ≤ n) в качестве корня. Таким образом, G(n) = ∑ F(i, n) для i от 1 до n. В частности, для базовых случаев есть только одна комбинация для построения BST из последовательности длиной 1 (только корень) или ничего (пустое дерево). То есть G(0) = 1, G(1) = 1. 3⃣Дана последовательность от 1 до n, мы выбираем число i из последовательности в качестве корня, тогда количество уникальных BST с указанным корнем, определенным как F(i, n), является декартовым произведением количества BST для его левого и правого поддеревьев, как показано ниже: Например, F(3,7) - количество уникальных деревьев BST с числом 3 в качестве корня. Для построения уникального BST из всей последовательности [1, 2, 3, 4, 5, 6, 7] с 3 в качестве корня, мы должны построить поддерево из его левой подпоследовательности [1, 2] и другое поддерево из правой подпоследовательности [4, 5, 6, 7], а затем соединить их вместе (то есть декартово произведение). Теперь хитрость заключается в том, что мы можем рассматривать количество уникальных BST из последовательности [1,2] как G(2), и количество уникальных BST из последовательности [4, 5, 6, 7] как G(4). Для G(n) не имеет значения содержание последовательности, а только длина последовательности. Следовательно, F(3,7) = G(2)⋅G(4). Обобщая пример, мы можем вывести следующую формулу: F(i, n) = G(i−1)⋅G(n−i) Объединяя формулы (1), (2), мы получаем рекурсивную формулу для G(n), то есть G(n) = ∑ G(i−1)⋅G(n−i) для i от 1 до n. Чтобы вычислить результат функции, мы начинаем с меньшего числа, так как значение G(n) зависит от значений G(0)...G(n−1). 😎 Решение: class Solution { func numTrees(_ n: Int) -> Int { var G = Array(repeating: 0, count: n + 1) G[0] = 1 G[1] = 1 for i in 2...n { for j in 1...i { G[i] += G[j - 1] * G[i - j] } } return G[n] } } Ставь 👍 и забирай 📚 Базу знаний
84
18
Задача: 1038. Binary Search Tree to Greater Sum Tree Сложность: medium Получив корень двоичного дерева поиска (BST), преобразуйте его в большее дерево таким образом, чтобы каждый ключ исходного BST был заменен на исходный ключ плюс сумма всех ключей, превышающих исходный ключ в BST. Напомним, что двоичное дерево поиска - это дерево, удовлетворяющее следующим ограничениям: левое поддерево узла содержит только узлы с ключами меньше, чем ключ узла. Правое поддерево узла содержит только узлы с ключами больше, чем ключ узла. И левое, и правое поддеревья должны быть двоичными деревьями поиска. Пример: Input: root = [4,1,6,0,2,5,7,null,null,null,3,null,null,null,8] Output: [30,36,21,36,35,26,15,null,null,null,33,null,null,null,8] 👨‍💻 Алгоритм: 1⃣Обратный обход in-order: Пройдите по дереву в порядке "правый, корень, левый" (обратный in-order обход). Это обеспечит посещение узлов в порядке убывания их значений. 2⃣Накопление суммы: Во время обхода поддерживайте переменную для хранения накопленной суммы. На каждом узле добавляйте значение узла к накопленной сумме и обновляйте значение узла этой накопленной суммой. 3⃣Преобразование узлов: Преобразуйте значение каждого узла в накопленную сумму. 😎 Решение: public class TreeNode { public var val: Int public var left: TreeNode? public var right: TreeNode? public init() { self.val = 0; self.left = nil; self.right = nil; } public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { self.val = val self.left = left self.right = right } } class Solution { var sum = 0 func bstToGst(_ root: TreeNode?) -> TreeNode? { reverseInorder(root) return root } func reverseInorder(_ node: TreeNode?) { guard let node = node else { return } reverseInorder(node.right) sum += node.val node.val = sum reverseInorder(node.left) } } Ставь 👍 и забирай 📚 Базу знаний
83
19
Привет, ребята! У нас для вас отличные новости — на easyoffer вышло сразу несколько крупных обновлений: 1. Автоотклики на HeadHunter Снова работают в полную силу — можно смело возвращаться к активному поиску. 2. Новый раздел «Резюмейкер» Теперь вы можете быстро создавать уникальные резюме, адаптированные под каждую вакансию, и сразу добавлять сопроводительное письмо. Это заметно повышает шансы получить приглашение на собеседование. 3. База вопросов стала чище Мы навели порядок и удалили около 30% дубликатов. Ориентироваться стало проще. –––––––––––––––––– 🔥 Акция в честь обновления Пожизненный тариф easyoffer PRO — по цене одного года. Успейте до 23 июня: 👉 https://easyoffer.ru/pro –––––––––––––––––– Что дальше? В ближайшие пару недель добавим ещё два раздела: 1. Сообщество с чатами по всем профессиональным направлениям. 2. Агрегатор вакансий, чтобы поиск работы стал ещё удобнее.
63
20
Задача: 1365. How Many Numbers Are Smaller Than the Current Number Сложность: easy Дан массив nums. Для каждого элемента nums[i] определите, сколько чисел в массиве меньше его. То есть, для каждого nums[i] вам нужно посчитать количество допустимых j, таких что j != i и nums[j] < nums[i]. Верните ответ в виде массива. Пример: Input: nums = [6,5,4,8] Output: [2,1,0,3] 👨‍💻 Алгоритм: 1⃣Создание копии и сортировка массива: Создайте отсортированную копию массива nums, чтобы легко находить количество элементов, меньших текущего. 2⃣Поиск индекса каждого элемента: Для каждого элемента nums[i] найдите его индекс в отсортированной копии массива. Этот индекс указывает количество элементов, меньших nums[i]. 3⃣Формирование ответа: Сформируйте массив ответов, где каждый элемент будет соответствовать количеству чисел, меньших текущего. 😎 Решение: class Solution { func smallerNumbersThanCurrent(_ nums: [Int]) -> [Int] { let sortedNums = nums.sorted() var result = [Int]() for num in nums { result.append(sortedNums.firstIndex(of: num)!) } return result } } Ставь 👍 и забирай 📚 Базу знаний
77