Задача: 91. Decode Ways
Сложность: medium
Сообщение, содержащее буквы от A до Z, можно закодировать в числа с использованием следующего соответствия:
- 'A' -> "1"
- 'B' -> "2"
- ...
- 'Z' -> "26"
Для декодирования закодированного сообщения все цифры должны быть сгруппированы и затем отображены обратно в буквы с использованием обратного соответствия (существует несколько способов). Например, "11106" можно представить как:
- "AAJF" с группировкой (1 1 10 6)
- "KJF" с группировкой (11 10 6)
Обратите внимание, что группировка (1 11 06) недопустима, потому что "06" не может быть преобразовано в 'F', так как "6" отличается от "06".
Для данной строки s, содержащей только цифры, верните количество способов декодирования.
Тестовые случаи сформированы таким образом, что ответ укладывается в 32-битное целое число.
Пример:
👨💻 Алгоритм:
1⃣ Входим в рекурсию с данной строкой, начиная с индекса 0.
2⃣ Для окончательного случая рекурсии мы проверяем конец строки. Если мы достигли конца строки, возвращаем 1. Каждый раз, когда мы входим в рекурсию, это для подстроки исходной строки. Если первый символ в подстроке равен 0, то прекращаем этот путь, возвращая 0. Таким образом, этот путь не будет влиять на количество способов.
3⃣ Мемоизация помогает снизить сложность, которая иначе была бы экспоненциальной. Мы проверяем словарь memo, чтобы увидеть, существует ли уже результат для данной подстроки. Если результат уже находится в memo, мы возвращаем этот результат. В противном случае количество способов для данной строки определяется путем рекурсивного вызова функции с индексом +1 для следующей подстроки и индексом +2 после проверки на валидность двузначного декодирования. Результат также сохраняется в memo с ключом как текущий индекс, чтобы сохранить его для будущих пересекающихся подзадач.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Сообщение, содержащее буквы от A до Z, можно закодировать в числа с использованием следующего соответствия:
- 'A' -> "1"
- 'B' -> "2"
- ...
- 'Z' -> "26"
Для декодирования закодированного сообщения все цифры должны быть сгруппированы и затем отображены обратно в буквы с использованием обратного соответствия (существует несколько способов). Например, "11106" можно представить как:
- "AAJF" с группировкой (1 1 10 6)
- "KJF" с группировкой (11 10 6)
Обратите внимание, что группировка (1 11 06) недопустима, потому что "06" не может быть преобразовано в 'F', так как "6" отличается от "06".
Для данной строки s, содержащей только цифры, верните количество способов декодирования.
Тестовые случаи сформированы таким образом, что ответ укладывается в 32-битное целое число.
Пример:
Input: s = "12"
Output: 2
Explanation: "12" could be decoded as "AB" (1 2) or "L" (12).
import Foundation
class Solution {
private var memo: [Int: Int] = [:]
private func recursiveWithMemo(_ index: Int, _ s: String) -> Int {
if index == s.count {
return 1
}
let startIndex = s.index(s.startIndex, offsetBy: index)
let firstChar = s[startIndex]
if firstChar == "0" {
return 0
}
if index == s.count - 1 {
return 1
}
if let cachedResult = memo[index] {
return cachedResult
}
let nextIndex = s.index(after: startIndex)
var answer = recursiveWithMemo(index + 1, s)
if index < s.count - 1 {
let secondIndex = s.index(after: nextIndex)
let range = startIndex..<secondIndex
let number = Int(s[range])!
if number <= 26 {
answer += recursiveWithMemo(index + 2, s)
}
}
memo[index] = answer
return answer
}
func numDecodings(_ s: String) -> Int {
return recursiveWithMemo(0, s)
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1337. The K Weakest Rows in a Matrix
Сложность: easy
Вам дана бинарная матрица размером m x n mat, состоящая из 1 (представляющих солдат) и 0 (представляющих гражданских лиц). Солдаты расположены перед гражданскими лицами. То есть, все 1 будут расположены слева от всех 0 в каждой строке.
Строка i слабее строки j, если выполнено одно из следующих условий:
Количество солдат в строке i меньше, чем в строке j.
Обе строки имеют одинаковое количество солдат, но i < j.
Верните индексы k самых слабых строк в матрице, упорядоченных от самой слабой к самой сильной.
Пример:
👨💻 Алгоритм:
1⃣ Вычислите силу каждой строки матрицы и поместите пары сила/индекс в массив. Для каждой строки подсчитайте количество единиц (солдат) до первой нуля (гражданского), чтобы определить силу строки.
2⃣ Отсортируйте массив пар по возрастанию силы, а в случае равенства силы — по возрастанию индекса. Для этого потребуется реализовать компаратор, который сравнивает сначала силу, а затем индекс.
3⃣ Извлеките первые k индексов из отсортированного массива и верните их. Эти индексы будут соответствовать k самым слабым строкам в порядке от самой слабой к самой сильной.
😎 Решение
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Вам дана бинарная матрица размером m x n mat, состоящая из 1 (представляющих солдат) и 0 (представляющих гражданских лиц). Солдаты расположены перед гражданскими лицами. То есть, все 1 будут расположены слева от всех 0 в каждой строке.
Строка i слабее строки j, если выполнено одно из следующих условий:
Количество солдат в строке i меньше, чем в строке j.
Обе строки имеют одинаковое количество солдат, но i < j.
Верните индексы k самых слабых строк в матрице, упорядоченных от самой слабой к самой сильной.
Пример:
Input: mat =
[[1,1,0,0,0],
[1,1,1,1,0],
[1,0,0,0,0],
[1,1,0,0,0],
[1,1,1,1,1]],
k = 3
Output: [2,0,3]
Explanation:
The number of soldiers in each row is:
- Row 0: 2
- Row 1: 4
- Row 2: 1
- Row 3: 2
- Row 4: 5
The rows ordered from weakest to strongest are [2,0,3,1,4].
class Solution {
func kWeakestRows(_ mat: [[Int]], _ k: Int) -> [Int] {
let m = mat.count
let n = mat[0].count
var pairs = [(Int, Int)]()
for i in 0..<m {
var strength = 0
for j in 0..<n {
if mat[i][j] == 0 { break }
strength += 1
}
pairs.append((strength, i))
}
pairs.sort { $0.0 == $1.0 ? $0.1 < $1.1 : $0.0 < $1.0 }
var indexes = [Int]()
for i in 0..<k {
indexes.append(pairs[i].1)
}
return indexes
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 109. Convert Sorted List to Binary Search Tree
Сложность: medium
Дана голова односвязного списка, элементы которого отсортированы в порядке возрастания. Преобразуйте его в сбалансированное по высоте бинарное дерево поиска.
Пример:
👨💻 Алгоритм:
1⃣ Поскольку нам дан односвязный список, а не массив, у нас нет прямого доступа к элементам списка по индексам. Нам нужно определить средний элемент односвязного списка. Мы можем использовать подход с двумя указателями для нахождения среднего элемента списка. В основном, у нас есть два указателя: slow_ptr и fast_ptr. slow_ptr перемещается на один узел за раз, тогда как fast_ptr перемещается на два узла за раз. К тому времени, как fast_ptr достигнет конца списка, slow_ptr окажется в середине списка. Для списка с четным количеством элементов любой из двух средних элементов может стать корнем BST.
2⃣ Как только мы находим средний элемент списка, мы отсоединяем часть списка слева от среднего элемента. Мы делаем это, сохраняя prev_ptr, который указывает на узел перед slow_ptr, т.е. prev_ptr.next = slow_ptr. Для отсоединения левой части мы просто делаем prev_ptr.next = None.
3⃣ Для создания сбалансированного по высоте BST нам нужно передать только голову связанного списка в функцию, которая преобразует его в BST. Таким образом, мы рекурсивно работаем с левой половиной списка, передавая оригинальную голову списка, и с правой половиной, передавая slow_ptr.next в качестве головы.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дана голова односвязного списка, элементы которого отсортированы в порядке возрастания. Преобразуйте его в сбалансированное по высоте бинарное дерево поиска.
Пример:
Input: head = [-10,-3,0,5,9]
Output: [0,-3,9,-10,null,5]
Explanation: One possible answer is [0,-3,9,-10,null,5], which represents the shown height balanced BST.
class Solution {
func sortedListToBST(_ head: ListNode?) -> TreeNode? {
if head == nil { return nil }
var mid = findMiddleElement(head)
var node = TreeNode(mid!.val)
if head === mid { return node }
node.left = sortedListToBST(head)
node.right = sortedListToBST(mid?.next)
return node
}
func findMiddleElement(_ head: ListNode?) -> ListNode? {
var prevPtr: ListNode? = nil
var slowPtr = head
var fastPtr = head
while fastPtr != nil && fastPtr!.next != nil {
prevPtr = slowPtr
slowPtr = slowPtr!.next
fastPtr = fastPtr!.next!.next
}
if prevPtr != nil { prevPtr!.next = nil }
return slowPtr
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 957. Prison Cells After N Days
Сложность: medium
Есть 8 тюремных камер в ряду, и каждая камера либо занята, либо пуста.
Каждый день статус камеры, занята она или пуста, меняется по следующим правилам:
Если у камеры два соседних соседа, которые оба заняты или оба пусты, то камера становится занятой.
В противном случае, она становится пустой.
Учтите, что поскольку тюрьма — это ряд, у первой и последней камер в ряду не может быть двух соседних соседей.
Вам дан целочисленный массив cells, где cells[i] == 1, если i-я камера занята, и cells[i] == 0, если i-я камера пуста, и вам дано целое число n.
Верните состояние тюрьмы после n дней (т.е. после n таких изменений, описанных выше).
Пример:
👨💻 Алгоритм:
1⃣ Преобразуйте текущее состояние камер в целое число с помощью битовой маски. Это позволит удобно отслеживать повторяющиеся состояния.
2⃣ Симулируйте изменение состояния камер день за днем, записывая каждое состояние в хэш-таблицу. Если обнаруживается повторяющееся состояние, вычислите длину цикла и уменьшите количество оставшихся дней с учетом этого цикла.
3⃣ Продолжайте симуляцию, пока не достигнете заданного числа дней, либо используйте цикл для ускорения процесса.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Есть 8 тюремных камер в ряду, и каждая камера либо занята, либо пуста.
Каждый день статус камеры, занята она или пуста, меняется по следующим правилам:
Если у камеры два соседних соседа, которые оба заняты или оба пусты, то камера становится занятой.
В противном случае, она становится пустой.
Учтите, что поскольку тюрьма — это ряд, у первой и последней камер в ряду не может быть двух соседних соседей.
Вам дан целочисленный массив cells, где cells[i] == 1, если i-я камера занята, и cells[i] == 0, если i-я камера пуста, и вам дано целое число n.
Верните состояние тюрьмы после n дней (т.е. после n таких изменений, описанных выше).
Пример:
Input: cells = [0,1,0,1,1,0,0,1], n = 7
Output: [0,0,1,1,0,0,0,0]
Explanation: The following table summarizes the state of the prison on each day:
Day 0: [0, 1, 0, 1, 1, 0, 0, 1]
Day 1: [0, 1, 1, 0, 0, 0, 0, 0]
Day 2: [0, 0, 0, 0, 1, 1, 1, 0]
Day 3: [0, 1, 1, 0, 0, 1, 0, 0]
Day 4: [0, 0, 0, 0, 0, 1, 0, 0]
Day 5: [0, 1, 1, 1, 0, 1, 0, 0]
Day 6: [0, 0, 1, 0, 1, 1, 0, 0]
Day 7: [0, 0, 1, 1, 0, 0, 0, 0]
class Solution {
func cellsToBitmap(_ cells: [Int]) -> Int {
var stateBitmap = 0
for cell in cells {
stateBitmap = (stateBitmap << 1) | cell
}
return stateBitmap
}
func nextDay(_ cells: [Int]) -> [Int] {
var newCells = Array(repeating: 0, count: cells.count)
for i in 1..<cells.count-1 {
newCells[i] = (cells[i-1] == cells[i+1]) ? 1 : 0
}
return newCells
}
func prisonAfterNDays(_ cells: [Int], _ N: Int) -> [Int] {
var cells = cells
var N = N
var seen = [Int: Int]()
var isFastForwarded = false
while N > 0 {
if !isFastForwarded {
let stateBitmap = cellsToBitmap(cells)
if let cycleLength = seen[stateBitmap] {
N %= cycleLength - N
isFastForwarded = true
} else {
seen[stateBitmap] = N
}
}
if N > 0 {
N -= 1
cells = nextDay(cells)
}
}
return cells
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 172. Factorial Trailing Zeroes
Сложность: medium
Дано целое число n, верните количество конечных нулей в n!.
Обратите внимание, что n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1.
Пример:
👨💻 Алгоритм:
1⃣ Вычислите факториал n:
Инициализируйте переменную nFactorial значением 1.
Для каждого i от 2 до n включительно умножайте nFactorial на i.
2⃣ Подсчитайте количество конечных нулей в nFactorial:
Инициализируйте переменную zeroCount значением 0.
Пока nFactorial делится на 10 без остатка, делите его на 10 и увеличивайте zeroCount на 1.
3⃣ Верните значение zeroCount как количество конечных нулей в n!.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дано целое число n, верните количество конечных нулей в n!.
Обратите внимание, что n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1.
Пример:
Input: n = 3
Output: 0
Explanation: 3! = 6, no trailing zero.
Инициализируйте переменную nFactorial значением 1.
Для каждого i от 2 до n включительно умножайте nFactorial на i.
Инициализируйте переменную zeroCount значением 0.
Пока nFactorial делится на 10 без остатка, делите его на 10 и увеличивайте zeroCount на 1.
func trailingZeroes(_ n: Int) -> Int {
var nFactorial = 1
for i in 2...n {
nFactorial *= i
}
var zeroCount = 0
var nFactorialBigInt = nFactorial
while nFactorialBigInt % 10 == 0 {
nFactorialBigInt /= 10
zeroCount += 1
}
return zeroCount
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1207. Unique Number of Occurrences
Сложность: easy
Дан массив целых чисел arr. Верните true, если количество вхождений каждого значения в массиве уникально, или false в противном случае.
Пример:
👨💻 Алгоритм:
1⃣ Сохраните частоты элементов массива arr в хэш-таблице freq.
2⃣ Итерируйтесь по хэш-таблице freq и вставьте частоты всех уникальных элементов массива arr в хэш-набор freqSet.
3⃣ Верните true, если размер хэш-набора freqSet равен размеру хэш-таблицы freq, иначе верните false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дан массив целых чисел arr. Верните true, если количество вхождений каждого значения в массиве уникально, или false в противном случае.
Пример:
Input: arr = [1,2,2,1,1,3]
Output: true
Explanation: The value 1 has 3 occurrences, 2 has 2 and 3 has 1. No two values have the same number of occurrences.
class Solution {
func uniqueOccurrences(_ arr: [Int]) -> Bool {
var freq: [Int: Int] = [:]
for num in arr {
freq[num, default: 0] += 1
}
let freqSet = Set(freq.values)
return freq.count == freqSet.count
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1219. Path with Maximum Gold
Сложность: medium
В золотом руднике размером m x n каждая ячейка содержит целое число, представляющее количество золота в этой ячейке, или 0, если она пуста.
Верните максимальное количество золота, которое вы можете собрать при следующих условиях:
- Каждый раз, когда вы находитесь в ячейке, вы собираете всё золото из этой ячейки.
- Из вашей позиции вы можете сделать один шаг влево, вправо, вверх или вниз.
- Вы не можете посещать одну и ту же ячейку более одного раза.
- Никогда не посещайте ячейку с 0 золотом.
- Вы можете начинать и прекращать сбор золота с любой позиции в сетке, которая содержит золото.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация и подготовка:
Инициализируйте константный массив DIRECTIONS для направления перемещений.
Определите количество строк и столбцов в сетке.
Инициализируйте переменную maxGold для хранения максимального количества собранного золота.
2⃣ Функция DFS и обратный трек:
Реализуйте функцию dfsBacktrack для поиска пути с максимальным золотом с помощью DFS и обратного трека.
Обрабатывайте базовый случай, проверяя выход за пределы сетки или ячейки без золота.
Пометьте текущую ячейку как посещённую и сохраните её значение.
Исследуйте каждую из четырёх смежных ячеек и обновите максимальное количество золота, если найден лучший путь.
Сбросьте текущую ячейку до её исходного значения для дальнейших исследований.
3⃣ Поиск максимального золота:
Используйте вложенные циклы для каждой ячейки в сетке, чтобы найти максимальное количество золота, начиная с этой ячейки, с помощью функции dfsBacktrack.
Обновите maxGold при нахождении лучшего пути.
Верните maxGold.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
В золотом руднике размером m x n каждая ячейка содержит целое число, представляющее количество золота в этой ячейке, или 0, если она пуста.
Верните максимальное количество золота, которое вы можете собрать при следующих условиях:
- Каждый раз, когда вы находитесь в ячейке, вы собираете всё золото из этой ячейки.
- Из вашей позиции вы можете сделать один шаг влево, вправо, вверх или вниз.
- Вы не можете посещать одну и ту же ячейку более одного раза.
- Никогда не посещайте ячейку с 0 золотом.
- Вы можете начинать и прекращать сбор золота с любой позиции в сетке, которая содержит золото.
Пример:
Input: grid = [[0,6,0],[5,8,7],[0,9,0]]
Output: 24
Explanation:
[[0,6,0],
[5,8,7],
[0,9,0]]
Path to get the maximum gold, 9 -> 8 -> 7.
Инициализируйте константный массив DIRECTIONS для направления перемещений.
Определите количество строк и столбцов в сетке.
Инициализируйте переменную maxGold для хранения максимального количества собранного золота.
Реализуйте функцию dfsBacktrack для поиска пути с максимальным золотом с помощью DFS и обратного трека.
Обрабатывайте базовый случай, проверяя выход за пределы сетки или ячейки без золота.
Пометьте текущую ячейку как посещённую и сохраните её значение.
Исследуйте каждую из четырёх смежных ячеек и обновите максимальное количество золота, если найден лучший путь.
Сбросьте текущую ячейку до её исходного значения для дальнейших исследований.
Используйте вложенные циклы для каждой ячейки в сетке, чтобы найти максимальное количество золота, начиная с этой ячейки, с помощью функции dfsBacktrack.
Обновите maxGold при нахождении лучшего пути.
Верните maxGold.
class Solution {
let directions = [0, 1, 0, -1, 0]
func getMaximumGold(_ grid: [[Int]]) -> Int {
var grid = grid
let rows = grid.count
let cols = grid[0].count
var maxGold = 0
for row in 0..<rows {
for col in 0..<cols {
maxGold = max(maxGold, dfsBacktrack(&grid, rows, cols, row, col))
}
}
return maxGold
}
func dfsBacktrack(_ grid: inout [[Int]], _ rows: Int, _ cols: Int, _ row: Int, _ col: Int) -> Int {
if row < 0 || col < 0 || row >= rows || col >= cols || grid[row][col] == 0 {
return 0
}
let originalVal = grid[row][col]
grid[row][col] = 0
var maxGold = 0
for i in 0..<4 {
maxGold = max(maxGold, dfsBacktrack(&grid, rows, cols, row + directions[i], col + directions[i + 1]))
}
grid[row][col] = originalVal
return maxGold + originalVal
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1273. Delete Tree Nodes
Сложность: medium
Дерево, укорененное в узле 0, задано следующим образом: количество узлов - nodes; значение i-го узла - value[i]; родитель i-го узла - parent[i]. Удалите все поддеревья, сумма значений узлов которых равна нулю. Верните количество оставшихся узлов в дереве.
Пример:
👨💻 Алгоритм:
1⃣ Постройте дерево из заданных узлов, значений и родителей.
2⃣ Используйте постфиксный обход для вычисления суммы значений в каждом поддереве и помечайте узлы для удаления, если их сумма равна нулю.
3⃣ Удалите отмеченные узлы и их поддеревья и верните количество оставшихся узлов.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дерево, укорененное в узле 0, задано следующим образом: количество узлов - nodes; значение i-го узла - value[i]; родитель i-го узла - parent[i]. Удалите все поддеревья, сумма значений узлов которых равна нулю. Верните количество оставшихся узлов в дереве.
Пример:
Input: nodes = 7, parent = [-1,0,0,1,2,2,2], value = [1,-2,4,0,-2,-1,-1]
Output: 2
class Solution {
func deleteTreeNodes(_ nodes: Int, _ parent: [Int], _ value: [Int]) -> Int {
var tree = [Int: [Int]]()
for i in 0..<nodes {
tree[parent[i], default: []].append(i)
}
func dfs(_ node: Int) -> (Int, Int) {
var totalSum = value[node]
var totalCount = 1
if let children = tree[node] {
for child in children {
let (childSum, childCount) = dfs(child)
totalSum += childSum
totalCount += childCount
}
}
return totalSum == 0 ? (0, 0) : (totalSum, totalCount)
}
return dfs(0).1
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 422. Valid Word Square
Сложность: easy
Дан массив строк words, верните true, если он образует правильный квадрат слов.
Последовательность строк образует правильный квадрат слов, если k-я строка и k-й столбец читаются одинаково, где 0 <= k < max(numRows, numColumns).
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте переменные: cols для максимальной длины слов в массиве, rows для количества строк в массиве words, и пустой массив newWords для хранения новых слов, представленных каждым столбцом.
2⃣ Итерация по массиву words, определение максимальной длины слова для cols, проверка, что количество строк равно количеству столбцов. Если условие не выполняется, возвращаем false.
3⃣ Для каждого столбца col от 0 до cols - 1, формируем строку newWord из символов на позиции (row, col) для каждой строки. Сохраняем newWord в массиве newWords. В конце, если newWords и words равны, возвращаем true, иначе false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дан массив строк words, верните true, если он образует правильный квадрат слов.
Последовательность строк образует правильный квадрат слов, если k-я строка и k-й столбец читаются одинаково, где 0 <= k < max(numRows, numColumns).
Пример:
Input: words = ["abcd","bnrt","crmy","dtye"]
Output: true
Explanation:
The 1st row and 1st column both read "abcd".
The 2nd row and 2nd column both read "bnrt".
The 3rd row and 3rd column both read "crmy".
The 4th row and 4th column both read "dtye".
Therefore, it is a valid word square.
class Solution {
func validWordSquare(_ words: [String]) -> Bool {
var cols = 0
let rows = words.count
var newWords = [String]()
for word in words {
cols = max(cols, word.count)
}
if cols != words[0].count || rows != cols {
return false
}
for col in 0..<cols {
var newWord = ""
for row in 0..<rows {
if col < words[row].count {
newWord.append(words[row][words[row].index(words[row].startIndex, offsetBy: col)])
}
}
newWords.append(newWord)
}
return words == newWords
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1382. Balance a Binary Search Tree
Сложность: medium
Дан корень бинарного дерева поиска. Верните сбалансированное бинарное дерево поиска с теми же значениями узлов. Если существует более одного ответа, верните любой из них.
Бинарное дерево поиска считается сбалансированным, если глубина двух поддеревьев каждого узла никогда не отличается более чем на 1.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация. Создайте пустой список inorder для хранения значений узлов после обхода в порядке возрастания.
2⃣ Выполнение обхода в порядке возрастания. Обойдите бинарное дерево поиска (BST) и заполните список inorder значениями узлов в отсортированном порядке.
3⃣ Перестроение сбалансированного BST. Определите рекурсивную функцию createBalancedBST, которая принимает список inorder, начальный индекс и конечный индекс в качестве параметров. Если начальный индекс больше конечного, верните null (или эквивалент). Вычислите средний индекс как середину текущего диапазона. Создайте новый узел дерева со значением в среднем индексе. Рекурсивно создайте левое поддерево, используя левую половину текущего диапазона. Рекурсивно создайте правое поддерево, используя правую половину текущего диапазона. Верните корень вновь построенного сбалансированного BST.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан корень бинарного дерева поиска. Верните сбалансированное бинарное дерево поиска с теми же значениями узлов. Если существует более одного ответа, верните любой из них.
Бинарное дерево поиска считается сбалансированным, если глубина двух поддеревьев каждого узла никогда не отличается более чем на 1.
Пример:
Input: root = [1,null,2,null,3,null,4,null,null]
Output: [2,1,3,null,null,null,4]
Explanation: This is not the only correct answer, [3,1,4,null,2] is also correct.
class Solution {
func balanceBST(_ root: TreeNode?) -> TreeNode? {
if root == nil { return nil }
let vineHead = TreeNode(0)
vineHead.right = root
var current: TreeNode? = vineHead
while current?.right != nil {
if current?.right?.left != nil {
rightRotate(current, current?.right)
} else {
current = current?.right
}
}
var nodeCount = 0
current = vineHead.right
while current != nil {
nodeCount += 1
current = current?.right
}
var m = Int(pow(2.0, floor(log2(Double(nodeCount + 1))))) - 1
makeRotations(vineHead, nodeCount - m)
while m > 1 {
m /= 2
makeRotations(vineHead, m)
}
let balancedRoot = vineHead.right
return balancedRoot
}
private func rightRotate(_ parent: TreeNode?, _ node: TreeNode?) {
let tmp = node?.left
node?.left = tmp?.right
tmp?.right = node
parent?.right = tmp
}
private func leftRotate(_ parent: TreeNode?, _ node: TreeNode?) {
let tmp = node?.right
node?.right = tmp?.left
tmp?.left = node
parent?.right = tmp
}
private func makeRotations(_ vineHead: TreeNode?, _ count: Int) {
var current = vineHead
for _ in 0..<count {
let tmp = current?.right
leftRotate(current, tmp)
current = current?.right
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from easyoffer
⏳ Осталось всего 14 дней до завершения краудфандинга
Сейчас самое подходящее время подключиться, если вы ждали или откладывали:
Все, кто поддержат проект сейчас, до релиза, получат:
🚀 PRO-доступ на 1 год по цене месячной подписки
➕ Бета-доступ к EasyOffer 2.0 (конец мая)
👉 Поддержать: https://planeta.ru/campaigns/easyoffer
Сейчас самое подходящее время подключиться, если вы ждали или откладывали:
Все, кто поддержат проект сейчас, до релиза, получат:
🚀 PRO-доступ на 1 год по цене месячной подписки
➕ Бета-доступ к EasyOffer 2.0 (конец мая)
👉 Поддержать: https://planeta.ru/campaigns/easyoffer
Задача: 84. Largest Rectangle in Histogram
Сложность: hard
Дан массив целых чисел heights, представляющий высоту столбцов гистограммы, где ширина каждого столбца равна 1. Верните площадь наибольшего прямоугольника в гистограмме.
Пример:
👨💻 Алгоритм:
1⃣ Введение в проблему:
Прежде всего, следует учитывать, что высота прямоугольника, образованного между любыми двумя столбиками, всегда будет ограничена высотой самого низкого столбика, находящегося между ними. Это можно понять, взглянув на рисунок ниже.
2⃣ Описание метода:
Таким образом, мы можем начать с рассмотрения каждой возможной пары столбиков и нахождения площади прямоугольника, образованного между ними, используя высоту самого низкого столбика между ними в качестве высоты и расстояние между ними в качестве ширины прямоугольника.
3⃣ Вычисление максимальной площади:
Таким образом, мы можем найти требуемый прямоугольник с максимальной площадью.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дан массив целых чисел heights, представляющий высоту столбцов гистограммы, где ширина каждого столбца равна 1. Верните площадь наибольшего прямоугольника в гистограмме.
Пример:
Input: heights = [2,1,5,6,2,3]
Output: 10
Explanation: The above is a histogram where width of each bar is 1.
The largest rectangle is shown in the red area, which has an area = 10 units.
Прежде всего, следует учитывать, что высота прямоугольника, образованного между любыми двумя столбиками, всегда будет ограничена высотой самого низкого столбика, находящегося между ними. Это можно понять, взглянув на рисунок ниже.
Таким образом, мы можем начать с рассмотрения каждой возможной пары столбиков и нахождения площади прямоугольника, образованного между ними, используя высоту самого низкого столбика между ними в качестве высоты и расстояние между ними в качестве ширины прямоугольника.
Таким образом, мы можем найти требуемый прямоугольник с максимальной площадью.
func largestRectangleArea(_ heights: [Int]) -> Int {
var maxArea = 0
for i in 0..<heights.count {
for j in i..<heights.count {
var minHeight = Int.max
for k in i...j {
minHeight = min(minHeight, heights[k])
}
maxArea = max(maxArea, minHeight * (j - i + 1))
}
}
return maxArea
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 921. Minimum Add to Make Parentheses Valid
Сложность: medium
Строка со скобками допустима тогда и только тогда, когда: это пустая строка, ее можно записать как AB (A, совмещенное с B), где A и B - допустимые строки, или ее можно записать как (A), где A - допустимая строка. Вам дана строка s со скобками. За один ход вы можете вставить скобку в любую позицию строки. Например, если s = "()))", вы можете вставить открывающую скобку в виде "(()))" или закрывающую скобку в виде "())))". Верните минимальное количество ходов, необходимое для того, чтобы сделать s допустимой.
Пример:
👨💻 Алгоритм:
1⃣ Инициализировать два счетчика open_needed и close_needed.
2⃣ Пройти по строке s символ за символом:
Если текущий символ - открывающая скобка (, увеличьте open_needed.
Если текущий символ - закрывающая скобка ), проверьте:
Если open_needed больше 0, уменьшите open_needed.
Иначе увеличьте close_needed.
3⃣ Суммируйте значения open_needed и close_needed, чтобы получить минимальное количество вставок.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Строка со скобками допустима тогда и только тогда, когда: это пустая строка, ее можно записать как AB (A, совмещенное с B), где A и B - допустимые строки, или ее можно записать как (A), где A - допустимая строка. Вам дана строка s со скобками. За один ход вы можете вставить скобку в любую позицию строки. Например, если s = "()))", вы можете вставить открывающую скобку в виде "(()))" или закрывающую скобку в виде "())))". Верните минимальное количество ходов, необходимое для того, чтобы сделать s допустимой.
Пример:
Input: n = 3, goal = 3, k = 1
Output: 6
Если текущий символ - открывающая скобка (, увеличьте open_needed.
Если текущий символ - закрывающая скобка ), проверьте:
Если open_needed больше 0, уменьшите open_needed.
Иначе увеличьте close_needed.
class Solution {
func minAddToMakeValid(_ s: String) -> Int {
var openNeeded = 0
var closeNeeded = 0
for char in s {
if char == "(" {
openNeeded += 1
} else if char == ")" {
if openNeeded > 0 {
openNeeded -= 1
} else {
closeNeeded += 1
}
}
}
return openNeeded + closeNeeded
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 26. Remove Duplicates from Sorted Array
Сложность: easy
Учитывая целочисленный массив чисел, отсортированный в неубывающем порядке, удалите дубликаты на месте так, чтобы каждый уникальный элемент появлялся только один раз. Относительный порядок элементов должен оставаться неизменным. Затем верните количество уникальных элементов в
Пример:
👨💻 Алгоритм:
1⃣ Используем указатель
2⃣ Проходим по массиву, начиная со второго элемента, и сравниваем с предыдущим.
3⃣ Если элемент новый, записываем его на позицию
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Учитывая целочисленный массив чисел, отсортированный в неубывающем порядке, удалите дубликаты на месте так, чтобы каждый уникальный элемент появлялся только один раз. Относительный порядок элементов должен оставаться неизменным. Затем верните количество уникальных элементов в
nums. Пример:
Input: nums = [1,1,2,2,2,3,4,4,5]
Output: 5
k для отслеживания позиции, куда вставлять уникальные элементы. 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
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 62. Unique Paths
Сложность: medium
На сетке размером m на n находится робот. Изначально робот расположен в верхнем левом углу (то есть, в клетке grid[0][0]). Робот пытается добраться до нижнего правого угла (то есть, в клетку grid[m - 1][n - 1]). Робот может двигаться только вниз или вправо в любой момент времени.
Даны два целых числа m и n, верните количество возможных уникальных путей, которые робот может пройти, чтобы достичь нижнего правого угла.
Тестовые случаи сгенерированы таким образом, что ответ будет меньше или равен 2 * 10^9.
Пример:
👨💻 Алгоритм:
1⃣ Инициализировать двумерный массив d[m][n] = количество путей. Сначала установить количество путей равным 1 для первой строки и первого столбца. Для упрощения можно инициализировать весь двумерный массив единицами.
2⃣ Проитерировать по всем "внутренним" ячейкам: d[col][row] = d[col - 1][row] + d[col][row - 1].
3⃣ Вернуть d[m - 1][n - 1].
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
На сетке размером m на n находится робот. Изначально робот расположен в верхнем левом углу (то есть, в клетке grid[0][0]). Робот пытается добраться до нижнего правого угла (то есть, в клетку grid[m - 1][n - 1]). Робот может двигаться только вниз или вправо в любой момент времени.
Даны два целых числа m и n, верните количество возможных уникальных путей, которые робот может пройти, чтобы достичь нижнего правого угла.
Тестовые случаи сгенерированы таким образом, что ответ будет меньше или равен 2 * 10^9.
Пример:
Input: m = 3, n = 7
Output: 28
class Solution {
func uniquePaths(_ m: Int, _ n: Int) -> Int {
var d = Array(repeating: Array(repeating: 1, count: n), count: m)
for col in 1..<m {
for row in 1..<n {
d[col][row] = d[col - 1][row] + d[col][row - 1]
}
}
return d[m - 1][n - 1]
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1008. Construct Binary Search Tree from Preorder Traversal
Сложность: medium
Дается массив целых чисел preorder, который представляет собой обход BST (т.е, гарантируется, что для заданных тестовых случаев всегда можно найти дерево двоичного поиска с заданными требованиями. Дерево двоичного поиска - это двоичное дерево, в котором для каждого узла любой потомок Node.left имеет значение строго меньше, чем Node.val, а любой потомок Node.right имеет значение строго больше, чем Node.val. При обходе бинарного дерева в предварительном порядке сначала выводится значение узла, затем обход Node.left, затем обход Node.right.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация переменных и функций:
Создайте класс узла дерева TreeNode с атрибутами val, left и right.
Инициализируйте индекс, который будет отслеживать текущую позицию в массиве preorder.
2⃣ Рекурсивная функция для построения дерева:
Создайте рекурсивную функцию constructBST с аргументами preorder, lower и upper, которые будут ограничивать значения узлов для текущей ветви дерева.
Если текущий индекс выходит за границы массива preorder, верните null.
Получите текущее значение из preorder и проверьте, находится ли оно в пределах допустимого диапазона [lower, upper]. Если нет, верните null.
3⃣ Создание узла и рекурсивное построение поддеревьев:
Создайте новый узел с текущим значением и увеличьте индекс.
Рекурсивно вызовите функцию constructBST для создания левого поддерева с обновленным верхним пределом (upper равным значению текущего узла).
Рекурсивно вызовите функцию constructBST для создания правого поддерева с обновленным нижним пределом (lower равным значению текущего узла).
Верните созданный узел.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дается массив целых чисел preorder, который представляет собой обход BST (т.е, гарантируется, что для заданных тестовых случаев всегда можно найти дерево двоичного поиска с заданными требованиями. Дерево двоичного поиска - это двоичное дерево, в котором для каждого узла любой потомок Node.left имеет значение строго меньше, чем Node.val, а любой потомок Node.right имеет значение строго больше, чем Node.val. При обходе бинарного дерева в предварительном порядке сначала выводится значение узла, затем обход Node.left, затем обход Node.right.
Пример:
Input: preorder = [8,5,1,7,10,12]
Output: [8,5,10,1,7,null,12]
Создайте класс узла дерева TreeNode с атрибутами val, left и right.
Инициализируйте индекс, который будет отслеживать текущую позицию в массиве preorder.
Создайте рекурсивную функцию constructBST с аргументами preorder, lower и upper, которые будут ограничивать значения узлов для текущей ветви дерева.
Если текущий индекс выходит за границы массива preorder, верните null.
Получите текущее значение из preorder и проверьте, находится ли оно в пределах допустимого диапазона [lower, upper]. Если нет, верните null.
Создайте новый узел с текущим значением и увеличьте индекс.
Рекурсивно вызовите функцию constructBST для создания левого поддерева с обновленным верхним пределом (upper равным значению текущего узла).
Рекурсивно вызовите функцию constructBST для создания правого поддерева с обновленным нижним пределом (lower равным значению текущего узла).
Верните созданный узел.
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 index = 0
func bstFromPreorder(_ preorder: [Int]) -> TreeNode? {
return constructBST(preorder, Int.min, Int.max)
}
func constructBST(_ preorder: [Int], _ lower: Int, _ upper: Int) -> TreeNode? {
if index == preorder.count {
return nil
}
let val = preorder[index]
if val < lower || val > upper {
return nil
}
index += 1
let root = TreeNode(val)
root.left = constructBST(preorder, lower, val)
root.right = constructBST(preorder, val, upper)
return root
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from easyoffer
🎉 Easyoffer 2.0 — самый успешный краудфандинг в истории рунета в категории "Технологии"!
Мы это сделали! За считанные часы после старта, благодаря вашей поддержке, проект не просто стартовал — он взлетел.
💸 Собрано: 2 276 840 рублей
Это не просто цифра — это ваше доверие, ваша вера в идею, и ваша инвестиция в будущее карьеры сотен (а скоро — тысяч) специалистов.
💼 Благодаря этой сумме мы уже:
— Наняли ещё пару разработчиков и аналитиков
— Запустили активный сбор и разметку новых данных
— Ускорили разработку и подняли планку качества
Спасибо каждому, кто поверил в нас на старте! Дальше — только масштабирование и развитие. Мы строим сервис, который станет must-have для всех, кто ищет работу в IT.
👉 Присоединяйтесь сейчас — это только начало.
Мы это сделали! За считанные часы после старта, благодаря вашей поддержке, проект не просто стартовал — он взлетел.
💸 Собрано: 2 276 840 рублей
Это не просто цифра — это ваше доверие, ваша вера в идею, и ваша инвестиция в будущее карьеры сотен (а скоро — тысяч) специалистов.
💼 Благодаря этой сумме мы уже:
— Наняли ещё пару разработчиков и аналитиков
— Запустили активный сбор и разметку новых данных
— Ускорили разработку и подняли планку качества
Спасибо каждому, кто поверил в нас на старте! Дальше — только масштабирование и развитие. Мы строим сервис, который станет must-have для всех, кто ищет работу в IT.
👉 Присоединяйтесь сейчас — это только начало.
Задача: 845. Longest Mountain in Array
Сложность: medium
Вы можете вспомнить, что массив arr является горным массивом тогда и только тогда, когда:
длина массива arr >= 3
Существует индекс i (счёт начинается с 0) такой, что:
arr[0] < arr[1] < ... < arr[i - 1] < arr[i]
arr[i] > arr[i + 1] > ... > arr[arr.length - 1]
Дан целочисленный массив arr, верните длину самой длинной подпоследовательности, которая является горной. Верните 0, если такой подпоследовательности нет.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте переменные для отслеживания текущего основания и максимальной длины горного массива.
2⃣ Для каждого индекса, который может быть началом горного массива, определите пиковый элемент и найдите правую границу горного массива.
3⃣ Если найден горный массив, обновите максимальную длину и переместите основание на конец текущего горного массива.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вы можете вспомнить, что массив arr является горным массивом тогда и только тогда, когда:
длина массива arr >= 3
Существует индекс i (счёт начинается с 0) такой, что:
arr[0] < arr[1] < ... < arr[i - 1] < arr[i]
arr[i] > arr[i + 1] > ... > arr[arr.length - 1]
Дан целочисленный массив arr, верните длину самой длинной подпоследовательности, которая является горной. Верните 0, если такой подпоследовательности нет.
Пример:
Input: arr = [2,1,4,7,3,2,5]
Output: 5
Explanation: The largest mountain is [1,4,7,3,2] which has length 5.
class Solution {
func longestMountain(_ arr: [Int]) -> Int {
let n = arr.count
var ans = 0
var base = 0
while base < n {
var end = base
if end + 1 < n && arr[end] < arr[end + 1] {
while end + 1 < n && arr[end] < arr[end + 1] {
end += 1
}
if end + 1 < n && arr[end] > arr[end + 1] {
while end + 1 < n && arr[end] > arr[end + 1] {
end += 1
}
ans = max(ans, end - base + 1)
}
}
base = max(end, base + 1)
}
return ans
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1535. Find the Winner of an Array Game
Сложность: medium
Дан целочисленный массив
Игра будет проводиться между первыми двумя элементами массива (т.е.
Верните число, которое выиграет игру.
Гарантируется, что у игры будет победитель.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте maxElement как максимальный элемент в arr, queue как очередь с элементами массива, кроме первого, curr = arr[0] и winstreak = 0.
2⃣ Пока очередь не пуста (или используйте бесконечный цикл), извлеките opponent из начала очереди. Если curr > opponent, добавьте opponent в конец очереди и увеличьте winstreak на 1. В противном случае добавьте curr в конец очереди, установите curr = opponent и winstreak = 1.
3⃣ Если winstreak = k или curr = maxElement, верните curr. Код никогда не должен достигать этой точки, так как гарантированно есть победитель. Верните любое значение.
😎 Решение
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан целочисленный массив
arr из различных целых чисел и целое число k.Игра будет проводиться между первыми двумя элементами массива (т.е.
arr[0] и arr[1]). В каждом раунде игры мы сравниваем arr[0] с arr[1], большее число побеждает и остается на позиции 0, а меньшее число перемещается в конец массива. Игра заканчивается, когда одно число выигрывает k подряд раундов.Верните число, которое выиграет игру.
Гарантируется, что у игры будет победитель.
Пример:
Input: arr = [2,1,3,5,4,6,7], k = 2
Output: 5
Explanation: Let's see the rounds of the game:
Round | arr | winner | win_count
1 | [2,1,3,5,4,6,7] | 2 | 1
2 | [2,3,5,4,6,7,1] | 3 | 1
3 | [3,5,4,6,7,1,2] | 5 | 1
4 | [5,4,6,7,1,2,3] | 5 | 2
So we can see that 4 rounds will be played and 5 is the winner because it wins 2 consecutive games.
class Solution {
func getWinner(_ arr: [Int], _ k: Int) -> Int {
var maxElement = arr[0]
var queue = Array(arr[1...])
for element in arr[1...] {
maxElement = max(maxElement, element)
}
var curr = arr[0]
var winstreak = 0
while !queue.isEmpty {
let opponent = queue.removeFirst()
if curr > opponent {
queue.append(opponent)
winstreak += 1
} else {
queue.append(curr)
curr = opponent
winstreak = 1
}
if winstreak == k || curr == maxElement {
return curr
}
}
return -1
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 917. Reverse Only Letters
Сложность: easy
Задав строку s, переверните ее в соответствии со следующими правилами: все символы, не являющиеся английскими буквами, остаются в той же позиции. Все английские буквы (строчные или прописные) должны быть перевернуты. Верните s после перевертывания.
Пример:
👨💻 Алгоритм:
1️⃣ Создать массив для хранения только английских букв из строки s.
2️⃣ Перевернуть массив с английскими буквами.
Пройти по строке s и заменить каждую английскую букву на соответствующую из перевернутого массива.
3️⃣ Вернуть результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Задав строку s, переверните ее в соответствии со следующими правилами: все символы, не являющиеся английскими буквами, остаются в той же позиции. Все английские буквы (строчные или прописные) должны быть перевернуты. Верните s после перевертывания.
Пример:
Input: s = "ab-cd"
Output: "dc-ba"
Пройти по строке s и заменить каждую английскую букву на соответствующую из перевернутого массива.
class Solution {
func reverseOnlyLetters(_ s: String) -> String {
var letters = [Character]()
for char in s {
if char.isLetter {
letters.append(char)
}
}
letters.reverse()
var result = [Character]()
var idx = 0
for char in s {
if char.isLetter {
result.append(letters[idx])
idx += 1
} else {
result.append(char)
}
}
return String(result)
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM