TGViewer
Channel Public Channel
Swift | LeetCode

Swift | LeetCode

@easy_swift_task

Сайт: https://easyoffer.ru/
Все каналы: t.me/+xGeAw6ckJ4liYzQy

Контакт для рекламы: @sendme_ads
Subscribers
1.3K
Photos
156
Videos
0
Links
1.5K

Showing posts older than #1545 · Back to latest

Older Posts 20 shown
Post #1544 81
Задача: 712. Minimum ASCII Delete Sum for Two Strings
Сложность: medium

Если даны две строки 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])).

😎 Решение:
func minimumDeleteSum(_ s1: String, _ s2: String) -> Int {
let s1Array = Array(s1)
let s2Array = Array(s2)
var dp = Array(repeating: Array(repeating: 0, count: s2Array.count + 1), count: s1Array.count + 1)
for i in 1...s1Array.count {
dp[i][0] = dp[i - 1][0] + Int(s1Array[i - 1].asciiValue!)
}
for j in 1...s2Array.count {
dp[0][j] = dp[0][j - 1] + Int(s2Array[j - 1].asciiValue!)
}
for i in 1...s1Array.count {
for j in 1...s2Array.count {
if s1Array[i - 1] == s2Array[j - 1] {
dp[i][j] = dp[i - 1][j - 1]
} else {
dp[i][j] = min(dp[i - 1][j] + Int(s1Array[i - 1].asciiValue!), dp[i][j - 1] + Int(s2Array[j - 1].asciiValue!))
}
}
}
return dp[s1Array.count][s2Array.count]
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1543 86
Задача: 664. Strange Printer
Сложность: hard

Существует странный принтер с двумя особыми свойствами:

Принтер может печатать последовательность одного и того же символа за раз.
На каждом шагу принтер может печатать новые символы, начиная и заканчивая в любом месте, при этом покрывая уже существующие символы.
Дана строка s. Верните минимальное количество ходов, необходимых для её печати.

Пример:
Input: s = "aaabbb"
Output: 2
Explanation: Print "aaa" first and then print "bbb".


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

1⃣Инициализация и подсчет:
Создайте двумерный массив dp, где dp[i][j] представляет минимальное количество ходов для печати подстроки s[i:j+1].

2⃣Динамическое программирование:
Если s[i] == s[j], тогда dp[i][j] = dp[i][j-1], так как последний символ совпадает с предыдущим.
В противном случае, dp[i][j] = min(dp[i][k] + dp[k+1][j]) для всех i <= k < j, чтобы найти минимальное количество ходов.


3⃣Возврат результата:
Возвратите dp[0][n-1], где n - длина строки s, что представляет минимальное количество ходов для печати всей строки.

😎 Решение:
class Solution {
func strangePrinter(_ s: String) -> Int {
let n = s.count
var dp = Array(repeating: Array(repeating: 0, count: n), count: n)
let chars = Array(s)

for length in 1...n {
for i in 0...(n - length) {
let j = i + length - 1
dp[i][j] = (i == j) ? 1 : dp[i][j - 1] + 1
for k in i..<j {
if chars[k] == chars[j] {
dp[i][j] = min(dp[i][j], dp[i][k] + (dp[k + 1][j - 1] if k + 1 <= j - 1 else 0))
}
}
}
}
return dp[0][n - 1]
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1542 98
Задача: 26. Remove Duplicates from Sorted Array
Сложность: easy


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

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


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

1⃣Используем указатель k для отслеживания позиции, куда вставлять уникальные элементы.

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

3⃣Если текущий элемент отличается от предыдущего, записываем его на позицию k и увеличиваем k.

😎Решение:
func removeDuplicates(_ nums: inout [Int]) -> Int {
if nums.isEmpty { return 0 }

var k = 1

for i in 1..<nums.count {
if nums[i] != nums[k - 1] {
nums[k] = nums[i]
k += 1
}
}

return k
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1541 88
Задача: 168. Excel Sheet Column Title
Сложность: easy

Дано целое число columnNumber, верните соответствующий заголовок столбца, как он отображается в таблице Excel.

Например:
A -> 1
B -> 2
C -> 3
Z -> 26
AA -> 27
AB -> 28

Пример:
Input: columnNumber = 1
Output: "A"


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

1⃣Инициализация пустой строки ans:
Создайте пустую строку ans, которая будет хранить заголовок столбца.

2⃣Циклическое преобразование числа в буквы:
Пока columnNumber больше 0, выполняйте следующие действия:
Вычтите 1 из columnNumber для корректировки индекса (Excel использует 1-индексацию).
Найдите символ, соответствующий остатку от деления columnNumber на 26, и добавьте его в начало строки ans.
Присвойте columnNumber значение от деления columnNumber на 26

3⃣Переворот и возврат результата:
Так как символы добавляются в начало строки, то по завершению цикла строка ans содержит заголовок столбца в обратном порядке. Переверните строку ans, чтобы представить её в правильном порядке.
Верните полученный заголовок столбца.

😎 Решение:
class Solution {
func convertToTitle(_ columnNumber: Int) -> String {
var columnNumber = columnNumber
var ans = ""

while columnNumber > 0 {
columnNumber -= 1
ans = "\(Character(UnicodeScalar(columnNumber % 26 + Int("A".unicodeScalars.first!.value))!))" + ans
columnNumber /= 26
}

return ans
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1540 88
Задача: 1086. High Five
Сложность: easy

Дан список оценок различных студентов, items, где items[i] = [IDi, scorei] представляет собой одну оценку студента с идентификатором IDi. Вычислите среднее значение пяти лучших оценок каждого студента.

Верните ответ в виде массива пар result, где result[j] = [IDj, topFiveAveragej] представляет студента с идентификатором IDj и его среднее значение пяти лучших оценок. Отсортируйте result по IDj в порядке возрастания.

Среднее значение пяти лучших оценок студента вычисляется путем сложения его пяти лучших оценок и деления на 5 с использованием целочисленного деления.

Пример:
Input: items = [[1,100],[7,100],[1,100],[7,100],[1,100],[7,100],[1,100],[7,100],[1,100],[7,100]]
Output: [[1,100],[7,100]]


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

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

2⃣Создайте список для хранения результата result. Переберите словарь и для каждого студента отсортируйте его оценки в порядке убывания, возьмите пять лучших оценок, вычислите их среднее значение (с целочисленным делением на 5) и добавьте пару [ID, topFiveAverage] в результат.

3⃣Отсортируйте список result по возрастанию ID студента и верните его.

😎 Решение:
class Solution {
func highFive(_ items: [[Int]]) -> [[Int]] {
let K = 5
let sortedItems = items.sorted {
if $0[0] != $1[0] {
return $0[0] < $1[0]
}
return $0[1] > $1[1]
}

var solution = [[Int]]()
var i = 0
while i < sortedItems.count {
let id = sortedItems[i][0]
var sum = 0
for k in i..<i+K {
sum += sortedItems[k][1]
}
while i < sortedItems.count && sortedItems[i][0] == id {
i += 1
}
solution.append([id, sum / K])
}
return solution
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1539 88
Задача: 979. Distribute Coins in Binary Tree
Сложность: medium

Вам дан корень бинарного дерева с n узлами, где каждый узел в дереве содержит node.val монет. Всего по всему дереву распределено n монет.

За один ход мы можем выбрать два смежных узла и переместить одну монету из одного узла в другой. Ход может быть как от родителя к ребенку, так и от ребенка к родителю.

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

Пример:
Input: root = [3,0,0]
Output: 2
Explanation: From the root of the tree, we move one coin to its left child, and one coin to its right child.


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

1⃣Инициализация и определение рекурсивной функции. Инициализируйте переменную moves = 0. Определите рекурсивную функцию dfs, которая считает количество перемещений монет. Базовый случай: если текущий узел равен null, верните 0.

2⃣Рекурсивный обход дерева. Внутри dfs вызовите dfs для левого и правого поддеревьев, чтобы получить количество монет, которые нужно переместить в каждом поддереве. Вычислите количество перемещений для текущего узла: добавьте абсолютные значения перемещаемых монет в moves.

3⃣Возвращение результата. Верните количество монет, которые текущий узел может передать своему родителю: значение узла плюс количество монет в левом и правом поддеревьях минус 1. Вызовите dfs от корня дерева и верните moves.

😎 Решение:
class Solution {
var moves = 0

func distributeCoins(_ root: TreeNode?) -> Int {
dfs(root)
return moves
}

private func dfs(_ current: TreeNode?) -> Int {
guard let current = current else { return 0 }
let leftCoins = dfs(current.left)
let rightCoins = dfs(current.right)
moves += abs(leftCoins) + abs(rightCoins)
return current.val - 1 + leftCoins + rightCoins
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1537 92
Задача: 834. Sum of Distances in Tree
Сложность: hard

Есть неориентированное связное дерево с n узлами, пронумерованными от 0 до n - 1, и n - 1 ребрами.

Вам даны целое число n и массив edges, где edges[i] = [ai, bi] указывает, что существует ребро между узлами ai и bi в дереве.

Верните массив answer длиной n, где answer[i] — это сумма расстояний между i-м узлом в дереве и всеми другими узлами.

Пример:
Input: n = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]]
Output: [8,12,6,10,10,10]
Explanation: The tree is shown above.
We can see that dist(0,1) + dist(0,2) + dist(0,3) + dist(0,4) + dist(0,5)
equals 1 + 1 + 2 + 2 + 2 = 8.
Hence, answer[0] = 8, and so on.


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

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

2⃣На основе полученных данных рассчитайте сумму расстояний для корня дерева.

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

😎 Решение:
class Solution {
var ans: [Int] = []
var count: [Int] = []
var graph: [[Int]] = []
var N: Int = 0

func sumOfDistancesInTree(_ N: Int, _ edges: [[Int]]) -> [Int] {
self.N = N
graph = Array(repeating: [], count: N)
ans = Array(repeating: 0, count: N)
count = Array(repeating: 1, count: N)

for edge in edges {
graph[edge[0]].append(edge[1])
graph[edge[1]].append(edge[0])
}

dfs(0, -1)
dfs2(0, -1)
return ans
}

func dfs(_ node: Int, _ parent: Int) {
for child in graph[node] {
if child != parent {
dfs(child, node)
count[node] += count[child]
ans[node] += ans[child] + count[child]
}
}
}

func dfs2(_ node: Int, _ parent: Int) {
for child in graph[node] {
if child != parent {
ans[child] = ans[node] - count[child] + N - count[child]
dfs2(child, node)
}
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1536 81
Задача: 1261. Find Elements in a Contaminated Binary Tree
Сложность: medium

Дано двоичное дерево со следующими правилами: root.val == 0 Если treeNode.val == x и treeNode.left != null, то treeNode.left.val == 2 * x + 1 Если treeNode.val == x и treeNode.right != null, то treeNode.right.val == 2 * x + 2 Теперь двоичное дерево загрязнено, то есть все treeNode.val были изменены на -1. Реализация класса FindElements: FindElements(TreeNode* root) Инициализирует объект с загрязненным двоичным деревом и восстанавливает его. bool find(int target) Возвращает true, если целевое значение существует в восстановленном двоичном дереве.

Пример:
Input
["FindElements","find","find"]
[[[-1,null,-1]],[1],[2]]
Output
[null,false,true]


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

1⃣Восстановление дерева: Начните с корневого узла, установите его значение на 0. Затем рекурсивно восстановите значения для всех узлов, используя правила left.val = 2 * parent.val + 1 и right.val = 2 * parent.val + 2.

2⃣Сохранение значений: Используйте структуру данных, такую как множество (set), для хранения всех восстановленных значений узлов.

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

😎 Решение:
class TreeNode {
var val: Int
var left: TreeNode?
var right: TreeNode?
init(_ val: Int) {
self.val = val
self.left = nil
self.right = nil
}
}

class FindElements {
private var root: TreeNode?
private var values: Set<Int>

init(_ root: TreeNode?) {
self.root = root
self.values = Set<Int>()
if let root = root {
root.val = 0
values.insert(0)
recover(root)
}
}

private func recover(_ node: TreeNode) {
if let left = node.left {
left.val = 2 * node.val + 1
values.insert(left.val)
recover(left)
}
if let right = node.right {
right.val = 2 * node.val + 2
values.insert(right.val)
recover(right)
}
}

func find(_ target: Int) -> Bool {
return values.contains(target)
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1535 84
Задача: 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)
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1534 87
Задача: 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
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1533 86
Задача: 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
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1532 98
Задача: 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
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1531 111
Задача: 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
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1530 107
Задача: 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]
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1529 102
Задача: 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
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1528 91
Задача: 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
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1527 97
Задача: 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
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1525 104
Задача: 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
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1524 104
Задача: 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
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1522 93
Задача: 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
}
}


Ставь 👍 и забирай 📚 Базу знаний
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →