Задача: 403. Frog Jump
Сложность: hard
Если задана строка num, представляющая неотрицательное целое число num, и целое число k, верните наименьшее возможное целое число после удаления k цифр из num.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация и структура данных
Создайте набор для хранения всех камней для быстрого доступа.
Используйте динамическое программирование с помощью словаря для отслеживания достижимых позиций и возможных прыжков.
2⃣ Итерация по камням
Пройдитесь по каждому камню и для каждого возможного прыжка (k-1, k, k+1) проверьте, если он ведет на существующий камень.
Если такой камень существует, добавьте его в набор возможных прыжков.
3⃣ Проверка достижения последнего камня
Если можно достичь последний камень с помощью одного из возможных прыжков, верните True.
Если после всех итераций последний камень не достигнут, верните False.Формирование результата:
Постройте итоговое число из цифр в стеке и удалите ведущие нули.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Если задана строка num, представляющая неотрицательное целое число num, и целое число k, верните наименьшее возможное целое число после удаления k цифр из num.
Пример:
Input: stones = [0,1,3,5,6,8,12,17]
Output: true
Создайте набор для хранения всех камней для быстрого доступа.
Используйте динамическое программирование с помощью словаря для отслеживания достижимых позиций и возможных прыжков.
Пройдитесь по каждому камню и для каждого возможного прыжка (k-1, k, k+1) проверьте, если он ведет на существующий камень.
Если такой камень существует, добавьте его в набор возможных прыжков.
Если можно достичь последний камень с помощью одного из возможных прыжков, верните True.
Если после всех итераций последний камень не достигнут, верните False.Формирование результата:
Постройте итоговое число из цифр в стеке и удалите ведущие нули.
class Solution {
func canCross(_ stones: [Int]) -> Bool {
var dp = [Int: Set<Int>]()
for stone in stones {
dp[stone] = Set<Int>()
}
dp[0]?.insert(0)
for stone in stones {
for jump in dp[stone]! {
for step in jump - 1...jump + 1 {
if step > 0, let _ = dp[stone + step] {
dp[stone + step]?.insert(step)
}
}
}
}
return !(dp[stones.last!]!.isEmpty)
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 632. Smallest Range Covering Elements from K Lists
Сложность: hard
У вас есть k списков отсортированных целых чисел в неубывающем порядке. Найдите наименьший диапазон, в который входит хотя бы одно число из каждого из k списков. Мы определяем, что диапазон [a, b] меньше диапазона [c, d], если b - a < d - c или a < c, если b - a == d - c.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация и сбор всех начальных элементов
Создайте массив для хранения текущих индексов каждого списка и используйте минимальную кучу для отслеживания текущих минимальных элементов из каждого списка.
2⃣ Нахождение минимального диапазона
Используйте кучу для извлечения минимального элемента и обновления текущего диапазона. Обновляйте максимальный элемент в текущем диапазоне при добавлении новых элементов.
3⃣ Проверка и обновление диапазона
Продолжайте обновлять кучу и диапазон, пока возможно. Завершите, когда один из списков исчерпан.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
У вас есть k списков отсортированных целых чисел в неубывающем порядке. Найдите наименьший диапазон, в который входит хотя бы одно число из каждого из k списков. Мы определяем, что диапазон [a, b] меньше диапазона [c, d], если b - a < d - c или a < c, если b - a == d - c.
Пример:
Input: nums = [[4,10,15,24,26],[0,9,12,20],[5,18,22,30]]
Output: [20,24]
Создайте массив для хранения текущих индексов каждого списка и используйте минимальную кучу для отслеживания текущих минимальных элементов из каждого списка.
Используйте кучу для извлечения минимального элемента и обновления текущего диапазона. Обновляйте максимальный элемент в текущем диапазоне при добавлении новых элементов.
Продолжайте обновлять кучу и диапазон, пока возможно. Завершите, когда один из списков исчерпан.
import Foundation
struct Element: Comparable {
let value: Int
let row: Int
let col: Int
static func < (lhs: Element, rhs: Element) -> Bool {
return lhs.value < rhs.value
}
}
class Solution {
func smallestRange(_ nums: [[Int]]) -> [Int] {
var minHeap = [Element]()
var maxValue = Int.min
for i in 0..<nums.count {
let element = Element(value: nums[i][0], row: i, col: 0)
minHeap.append(element)
maxValue = max(maxValue, nums[i][0])
}
minHeap.sort()
var rangeStart = 0
var rangeEnd = Int.max
while minHeap.count == nums.count {
let minElement = minHeap.removeFirst()
if maxValue - minElement.value < rangeEnd - rangeStart {
rangeStart = minElement.value
rangeEnd = maxValue
}
if minElement.col + 1 < nums[minElement.row].count {
let newValue = nums[minElement.row][minElement.col + 1]
let newElement = Element(value: newValue, row: minElement.row, col: minElement.col + 1)
minHeap.append(newElement)
maxValue = max(maxValue, newValue)
minHeap.sort()
}
}
return [rangeStart, rangeEnd]
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 711. Number of Distinct Islands II
Сложность: hard
Вам дана двоичная матричная сетка m x n. Остров - это группа 1 (представляющая сушу), соединенных в четырех направлениях (горизонтальном или вертикальном). Можно предположить, что все четыре края сетки окружены водой. Остров считается одинаковым с другим, если они имеют одинаковую форму, или имеют одинаковую форму после поворота (только на 90, 180 или 270 градусов) или отражения (влево/вправо или вверх/вниз). Верните количество разных островов.
Пример:
👨💻 Алгоритм:
1⃣ Пройдите по каждому элементу матрицы, если найдена земля (1), выполните DFS для обнаружения всех связанных с этим островом земель и сохраните форму острова.
2⃣ Нормализуйте форму острова, применив все возможные повороты и отражения, чтобы найти каноническую форму.
3⃣ Используйте множество для хранения всех уникальных канонических форм и верните размер этого множества.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Вам дана двоичная матричная сетка m x n. Остров - это группа 1 (представляющая сушу), соединенных в четырех направлениях (горизонтальном или вертикальном). Можно предположить, что все четыре края сетки окружены водой. Остров считается одинаковым с другим, если они имеют одинаковую форму, или имеют одинаковую форму после поворота (только на 90, 180 или 270 градусов) или отражения (влево/вправо или вверх/вниз). Верните количество разных островов.
Пример:
Input: grid = [[1,1,0,0,0],[1,0,0,0,0],[0,0,0,0,1],[0,0,0,1,1]]
Output: 1
class Solution {
func numDistinctIslands2(_ grid: [[Int]]) -> Int {
var grid = grid
var uniqueIslands = Set<[[(Int, Int)]]>()
func dfs(_ i: Int, _ j: Int) -> [(Int, Int)] {
var shape = [(Int, Int)]()
var stack = [(i, j)]
while !stack.isEmpty {
let (x, y) = stack.removeLast()
if x >= 0 && x < grid.count && y >= 0 && y < grid[0].count && grid[x][y] == 1 {
grid[x][y] = 0
shape.append((x - i, y - j))
stack.append((x + 1, y))
stack.append((x - 1, y))
stack.append((x, y + 1))
stack.append((x, y - 1))
}
}
return shape
}
func normalize(_ shape: [(Int, Int)]) -> [[(Int, Int)]] {
var shapes = Array(repeating: [(Int, Int)](), count: 8)
for (x, y) in shape {
shapes[0].append((x, y))
shapes[1].append((x, -y))
shapes[2].append((-x, y))
shapes[3].append((-x, -y))
shapes[4].append((y, x))
shapes[5].append((y, -x))
shapes[6].append((-y, x))
shapes[7].append((-y, -x))
}
for i in 0..<8 {
shapes[i].sort(by: { $0.0 == $1.0 ? $0.1 < $1.1 : $0.0 < $1.0 })
}
return shapes
}
for i in 0..<grid.count {
for j in 0..<grid[0].count {
if grid[i][j] == 1 {
let shape = dfs(i, j)
let normalizedShape = normalize(shape)
if let minShape = normalizedShape.min(by: { $0.lexicographicallyPrecedes($1) }) {
uniqueIslands.insert(minShape)
}
}
}
}
return uniqueIslands.count
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 566. Reshape the Matrix
Сложность: easy
В MATLAB есть удобная функция под названием reshape, которая может преобразовать матрицу размером m x n в новую матрицу с другим размером r x c, сохраняя исходные данные.
Вам дана матрица m x n mat и два целых числа r и c, представляющие количество строк и столбцов желаемой преобразованной матрицы.
Преобразованная матрица должна быть заполнена всеми элементами исходной матрицы в том же порядке обхода строк, в котором они были.
Если операция преобразования с заданными параметрами возможна и допустима, выведите новую преобразованную матрицу; в противном случае выведите исходную матрицу.
Пример:
👨💻 Алгоритм:
1⃣ Проверить, можно ли преобразовать матрицу с заданными параметрами r и c. Это возможно, если произведение m * n равно произведению r * c. Если преобразование невозможно, вернуть исходную матрицу.
2⃣ Создать новый массив для хранения преобразованной матрицы. Перебрать все элементы исходной матрицы и вставить их в новый массив в порядке обхода строк.
3⃣ Вернуть преобразованную матрицу, если преобразование возможно, иначе вернуть исходную матрицу.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
В MATLAB есть удобная функция под названием reshape, которая может преобразовать матрицу размером m x n в новую матрицу с другим размером r x c, сохраняя исходные данные.
Вам дана матрица m x n mat и два целых числа r и c, представляющие количество строк и столбцов желаемой преобразованной матрицы.
Преобразованная матрица должна быть заполнена всеми элементами исходной матрицы в том же порядке обхода строк, в котором они были.
Если операция преобразования с заданными параметрами возможна и допустима, выведите новую преобразованную матрицу; в противном случае выведите исходную матрицу.
Пример:
Input: mat = [[1,2],[3,4]], r = 1, c = 4
Output: [[1,2,3,4]]
class Solution {
func matrixReshape(_ mat: [[Int]], _ r: Int, _ c: Int) -> [[Int]] {
let m = mat.count
let n = mat[0].count
if m * n != r * c {
return mat
}
var reshapedMatrix = Array(repeating: Array(repeating: 0, count: c), count: r)
var row = 0
var col = 0
for i in 0..<m {
for j in 0..<n {
reshapedMatrix[row][col] = mat[i][j]
col += 1
if col == c {
col = 0
row += 1
}
}
}
return reshapedMatrix
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 70. Climbing Stairs
Сложность: easy
Ты поднимаешься по лестнице. Чтобы добраться до вершины, нужно преодолеть n ступенек.
Каждый раз ты можешь подняться на 1 или 2 ступеньки. Сколькими различными способами ты можешь добраться до вершины?
Пример:
👨💻 Алгоритм:
1⃣ В этом методе грубой силы мы рассматриваем все возможные комбинации шагов, то есть 1 и 2, на каждом шаге.
2⃣ На каждом шаге мы вызываем функцию climbStairs для шага 1 и шага 2, и возвращаем сумму возвращаемых значений обеих функций.
3⃣ Формула вызова функции: climbStairs(i, n) = climbStairs(i+1, n) + climbStairs(i+2, n), где i определяет текущий шаг, а n — целевой шаг.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Ты поднимаешься по лестнице. Чтобы добраться до вершины, нужно преодолеть n ступенек.
Каждый раз ты можешь подняться на 1 или 2 ступеньки. Сколькими различными способами ты можешь добраться до вершины?
Пример:
Input: n = 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps
func climbStairs(_ n: Int) -> Int {
return climbStairsHelper(0, n)
}
func climbStairsHelper(_ i: Int, _ n: Int) -> Int {
if i > n {
return 0
}
if i == n {
return 1
}
return climbStairsHelper(i + 1, n) + climbStairsHelper(i + 2, n)
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 1502. Can Make Arithmetic Progression From Sequence
Сложность: easy
Последовательность чисел называется арифметической прогрессией, если разница между любыми двумя последовательными элементами одинаковая.
Дан массив чисел arr, верните true, если массив можно переставить так, чтобы он образовал арифметическую прогрессию. В противном случае верните false.
Пример:
👨💻 Алгоритм:
1⃣ Отсортируйте массив arr.
2⃣ Запишите разницу первой пары элементов: diff = arr[1] - arr[0].
3⃣ Итерируйтесь по отсортированному массиву начиная с i = 2, проверяя, равна ли разница каждой пары элементов значению diff. Если нет, верните False. Если итерация завершена без нахождения различий, верните True.
😎 Решение
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Последовательность чисел называется арифметической прогрессией, если разница между любыми двумя последовательными элементами одинаковая.
Дан массив чисел arr, верните true, если массив можно переставить так, чтобы он образовал арифметическую прогрессию. В противном случае верните false.
Пример:
Input: arr = [3,5,1]
Output: true
Explanation: We can reorder the elements as [1,3,5] or [5,3,1] with differences 2 and -2 respectively, between each consecutive elements.
class Solution {
func canMakeArithmeticProgression(_ arr: [Int]) -> Bool {
let arr = arr.sorted()
let diff = arr[1] - arr[0]
for i in 2..<arr.count {
if arr[i] - arr[i - 1] != diff {
return false
}
}
return true
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 525. Contiguous Array
Сложность: medium
Дан бинарный массив nums. Верните максимальную длину непрерывного подмассива с равным количеством 0 и 1.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте переменную count для отслеживания разности между количеством 1 и 0, и переменную max_length для хранения максимальной длины подмассива. Создайте хеш-таблицу map для хранения первых встреч каждого значения count. Добавьте начальное значение (0, -1) в хеш-таблицу.
2⃣ Итеративно пройдите по массиву nums. На каждой итерации обновляйте значение count (увеличивайте на 1 для 1 и уменьшайте на 1 для 0). Если текущее значение count уже существует в хеш-таблице, вычислите длину подмассива между текущим индексом и индексом из хеш-таблицы. Обновите max_length, если текущий подмассив длиннее.
3⃣ Если текущее значение count не существует в хеш-таблице, добавьте его с текущим индексом. После завершения итерации верните max_length.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан бинарный массив nums. Верните максимальную длину непрерывного подмассива с равным количеством 0 и 1.
Пример:
Input: nums = [0,1]
Output: 2
Explanation: [0, 1] is the longest contiguous subarray with an equal number of 0 and 1.
class Solution {
func findMaxLength(_ nums: [Int]) -> Int {
var countMap: [Int: Int] = [0: -1]
var maxLength = 0
var count = 0
for i in 0..<nums.count {
count += (nums[i] == 1 ? 1 : -1)
if let prevIndex = countMap[count] {
maxLength = max(maxLength, i - prevIndex)
} else {
countMap[count] = i
}
}
return maxLength
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1074. Number of Submatrices That Sum to Target
Сложность: hard
Дана матрица и целевое значение. Верните количество непустых подматриц, сумма элементов которых равна целевому значению.
Подматрица x1, y1, x2, y2 — это набор всех ячеек matrix[x][y] с x1 <= x <= x2 и y1 <= y <= y2.
Две подматрицы (x1, y1, x2, y2) и (x1', y1', x2', y2') различны, если у них есть какая-то различающаяся координата: например, если x1 != x1'.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте результат: count = 0. Вычислите количество строк: r = len(matrix) и количество столбцов: c = len(matrix[0]). Вычислите двумерную префиксную сумму ps, выделив еще одну строку и еще один столбец для нулевых значений.
2⃣ Итерируйте по строкам: r1 от 1 до r и r2 от r1 до r. Внутри этого двойного цикла фиксируйте левые и правые границы строк и инициализируйте хэш-таблицу для хранения префиксных сумм. Итерируйте по столбцам от 1 до c + 1, вычислите текущую префиксную сумму 1D curr_sum и увеличьте count на количество матриц, сумма которых равна target.
3⃣ Добавьте текущую префиксную сумму 1D в хэш-таблицу. Когда все итерации завершены, верните count.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дана матрица и целевое значение. Верните количество непустых подматриц, сумма элементов которых равна целевому значению.
Подматрица x1, y1, x2, y2 — это набор всех ячеек matrix[x][y] с x1 <= x <= x2 и y1 <= y <= y2.
Две подматрицы (x1, y1, x2, y2) и (x1', y1', x2', y2') различны, если у них есть какая-то различающаяся координата: например, если x1 != x1'.
Пример:
Input: matrix = [[0,1,0],[1,1,1],[0,1,0]], target = 0
Output: 4
Explanation: The four 1x1 submatrices that only contain 0.
class Solution {
func numSubmatrixSumTarget(_ matrix: [[Int]], _ target: Int) -> Int {
let r = matrix.count, c = matrix[0].count
var ps = Array(repeating: Array(repeating: 0, count: c + 1), count: r + 1)
for i in 1...r {
for j in 1...c {
ps[i][j] = ps[i - 1][j] + ps[i][j - 1] - ps[i - 1][j - 1] + matrix[i - 1][j - 1]
}
}
var count = 0
var currSum: Int
var h = [Int: Int]()
for r1 in 1...r {
for r2 in r1...r {
h.removeAll()
h[0] = 1
for col in 1...c {
currSum = ps[r2][col] - ps[r1 - 1][col]
count += h[currSum - target, default: 0]
h[currSum, default: 0] += 1
}
}
}
return count
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1006. Clumsy Factorial
Сложность: medium
Факториал целого положительного числа n - это произведение всех целых положительных чисел, меньших или равных n. Например, факториал(10) = 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1.
Мы составляем неуклюжий факториал, используя целые числа в порядке убывания, заменяя операции умножения на фиксированную последовательность операций с умножением "*", делением "/", сложением "+" и вычитанием "-" в этом порядке. Например, clumsy(10) = 10 * 9 / 8 + 7 - 6 * 5 / 4 + 3 - 2 * 1. Однако эти операции по-прежнему применяются с использованием обычного порядка операций арифметики. Мы выполняем все шаги умножения и деления перед шагами сложения и вычитания, а шаги умножения и деления выполняются слева направо. Кроме того, деление, которое мы используем, является делением с полом, так что 10 * 9 / 8 = 90 / 8 = 11. Учитывая целое число n, верните неуклюжий факториал n.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация переменных и обработка первых трех чисел:
Создайте переменные для хранения результата и текущего значения.
Если n меньше или равен 3, обработайте случай отдельно, выполняя операции в порядке убывания, и верните результат.
2⃣ Выполнение операций в цикле:
Создайте цикл, который будет обрабатывать числа от n до 1 в порядке убывания.
В цикле выполняйте операции *, /, +, и - последовательно.
Обновляйте текущий результат на каждом шаге в зависимости от остатка от деления текущего индекса на 4.
3⃣ Учет оставшихся операций и возврат результата:
После завершения цикла добавьте или вычтите оставшиеся числа (если есть) к результату.
Верните окончательный результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Факториал целого положительного числа n - это произведение всех целых положительных чисел, меньших или равных n. Например, факториал(10) = 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1.
Мы составляем неуклюжий факториал, используя целые числа в порядке убывания, заменяя операции умножения на фиксированную последовательность операций с умножением "*", делением "/", сложением "+" и вычитанием "-" в этом порядке. Например, clumsy(10) = 10 * 9 / 8 + 7 - 6 * 5 / 4 + 3 - 2 * 1. Однако эти операции по-прежнему применяются с использованием обычного порядка операций арифметики. Мы выполняем все шаги умножения и деления перед шагами сложения и вычитания, а шаги умножения и деления выполняются слева направо. Кроме того, деление, которое мы используем, является делением с полом, так что 10 * 9 / 8 = 90 / 8 = 11. Учитывая целое число n, верните неуклюжий факториал n.
Пример:
Input: nums = [4,2,3], k = 1
Output: 5
Создайте переменные для хранения результата и текущего значения.
Если n меньше или равен 3, обработайте случай отдельно, выполняя операции в порядке убывания, и верните результат.
Создайте цикл, который будет обрабатывать числа от n до 1 в порядке убывания.
В цикле выполняйте операции *, /, +, и - последовательно.
Обновляйте текущий результат на каждом шаге в зависимости от остатка от деления текущего индекса на 4.
После завершения цикла добавьте или вычтите оставшиеся числа (если есть) к результату.
Верните окончательный результат.
class Solution {
func clumsy(_ n: Int) -> Int {
if n == 0 { return 0 }
if n == 1 { return 1 }
if n == 2 { return 2 * 1 }
if n == 3 { return 3 * 2 / 1 }
var res = n * (n - 1) / (n - 2)
var n = n - 3
if n > 0 { res += n }
n -= 1
while n > 0 {
res -= n * (n - 1) / (n - 2)
n -= 3
if n > 0 { res += n }
n -= 1
}
return res
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 926. Flip String to Monotone Increasing
Сложность: medium
Двоичная строка является монотонно возрастающей, если она состоит из некоторого количества 0 (возможно, ни одного), за которым следует некоторое количество 1 (также возможно, ни одного). Вам дана двоичная строка s. Вы можете перевернуть s[i], изменив ее значение с 0 на 1 или с 1 на 0.
Пример:
👨💻 Алгоритм:
1⃣ Создать массив left для подсчета количества операций, чтобы сделать подстроку до текущего индекса монотонной (только 0).
2⃣ Создать массив right для подсчета количества операций, чтобы сделать подстроку после текущего индекса монотонной (только 1).
Пройти по строке и заполнить массивы left и right.
3⃣ Пройти по строке и найти минимальное количество операций, чтобы сделать всю строку монотонной.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Двоичная строка является монотонно возрастающей, если она состоит из некоторого количества 0 (возможно, ни одного), за которым следует некоторое количество 1 (также возможно, ни одного). Вам дана двоичная строка s. Вы можете перевернуть s[i], изменив ее значение с 0 на 1 или с 1 на 0.
Пример:
Input: s = "00110"
Output: 1
Пройти по строке и заполнить массивы left и right.
class Solution {
func minFlipsMonoIncr(_ s: String) -> Int {
let n = s.count
var left = [Int](repeating: 0, count: n + 1)
var right = [Int](repeating: 0, count: n + 1)
let sArray = Array(s)
for i in 0..<n {
left[i + 1] = left[i] + (sArray[i] == "1" ? 1 : 0)
}
for i in (0..<n).reversed() {
right[i] = right[i + 1] + (sArray[i] == "0" ? 1 : 0)
}
var result = Int.max
for i in 0...n {
result = min(result, left[i] + right[i])
}
return result
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1533. Find the Index of the Large Integer
Сложность: medium
У нас есть целочисленный массив arr, в котором все элементы равны, кроме одного элемента, который больше остальных. Вам не будет предоставлен прямой доступ к массиву, вместо этого у вас будет API ArrayReader, который имеет следующие функции:
int compareSub(int l, int r, int x, int y): где 0 <= l, r, x, y < ArrayReader.length(), l <= r и x <= y. Функция сравнивает сумму подмассива arr[l..r] с суммой подмассива arr[x..y] и возвращает:
1, если arr[l] + arr[l+1] + ... + arr[r] > arr[x] + arr[x+1] + ... + arr[y].
0, если arr[l] + arr[l+1] + ... + arr[r] == arr[x] + arr[x+1] + ... + arr[y].
-1, если arr[l] + arr[l+1] + ... + arr[r] < arr[x] + arr[x+1] + ... + arr[y].
int length(): Возвращает размер массива.
Вам разрешено вызывать compareSub() не более 20 раз. Вы можете предположить, что обе функции работают за O(1) время.
Верните индекс массива arr, который содержит наибольший элемент.
Пример:
👨💻 Алгоритм:
1⃣ Установите left = 0 и length = reader.length. left - это самый левый индекс нашего поискового пространства, а length - это размер нашего поискового пространства. Индекс большего числа всегда должен находиться в пределах [left, left + length).
2⃣ Пока length > 1:
— Обновите length до length / 2.
— Установите cmp равным reader.compareSub(left, left + length - 1, left + length, left + length + length - 1).
— Если cmp равно 0, верните left + length + length, так как оставшийся элемент является большим числом. Это возможно только если текущее поисковое пространство имеет нечетную длину, поэтому если у нас четная длина, мы не беспокоимся об этом случае.
— Если cmp равно -1, увеличьте left на length.
— Если cmp равно 1, ничего не делайте, так как наш left остается прежним и мы уже разделили length на 2.
3⃣ Верните left. Это стандартная процедура для бинарного поиска, когда если поиск завершается без возврата, то левая граница указывает на ответ.
😎 Решение
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
У нас есть целочисленный массив arr, в котором все элементы равны, кроме одного элемента, который больше остальных. Вам не будет предоставлен прямой доступ к массиву, вместо этого у вас будет API ArrayReader, который имеет следующие функции:
int compareSub(int l, int r, int x, int y): где 0 <= l, r, x, y < ArrayReader.length(), l <= r и x <= y. Функция сравнивает сумму подмассива arr[l..r] с суммой подмассива arr[x..y] и возвращает:
1, если arr[l] + arr[l+1] + ... + arr[r] > arr[x] + arr[x+1] + ... + arr[y].
0, если arr[l] + arr[l+1] + ... + arr[r] == arr[x] + arr[x+1] + ... + arr[y].
-1, если arr[l] + arr[l+1] + ... + arr[r] < arr[x] + arr[x+1] + ... + arr[y].
int length(): Возвращает размер массива.
Вам разрешено вызывать compareSub() не более 20 раз. Вы можете предположить, что обе функции работают за O(1) время.
Верните индекс массива arr, который содержит наибольший элемент.
Пример:
Input: arr = [7,7,7,7,10,7,7,7]
Output: 4
Explanation: The following calls to the API
reader.compareSub(0, 0, 1, 1) // returns 0 this is a query comparing the sub-array (0, 0) with the sub array (1, 1), (i.e. compares arr[0] with arr[1]).
Thus we know that arr[0] and arr[1] doesn't contain the largest element.
reader.compareSub(2, 2, 3, 3) // returns 0, we can exclude arr[2] and arr[3].
reader.compareSub(4, 4, 5, 5) // returns 1, thus for sure arr[4] is the largest element in the array.
Notice that we made only 3 calls, so the answer is valid.
— Обновите length до length / 2.
— Установите cmp равным reader.compareSub(left, left + length - 1, left + length, left + length + length - 1).
— Если cmp равно 0, верните left + length + length, так как оставшийся элемент является большим числом. Это возможно только если текущее поисковое пространство имеет нечетную длину, поэтому если у нас четная длина, мы не беспокоимся об этом случае.
— Если cmp равно -1, увеличьте left на length.
— Если cmp равно 1, ничего не делайте, так как наш left остается прежним и мы уже разделили length на 2.
class Solution {
func getIndex(_ reader: ArrayReader) -> Int {
var left = 0
var length = reader.length()
while length > 1 {
length /= 2
let cmp = reader.compareSub(left, left + length - 1, left + length, left + 2 * length - 1)
if cmp == 0 {
return left + 2 * length
}
if cmp < 0 {
left += length
}
}
return left
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 929. Unique Email Addresses
Сложность: easy
Вам дана сеть из n узлов, представленная в виде графа с матрицей смежности n x n, где i-й узел непосредственно связан с j-м узлом, если graph[i][j] == 1. Некоторые узлы изначально заражены вредоносным ПО. Если два узла соединены напрямую и хотя бы один из них заражен вредоносным ПО, то оба узла будут заражены вредоносным ПО. Такое распространение вредоносного ПО будет продолжаться до тех пор, пока больше не останется ни одного узла, зараженного таким образом. Предположим, что M(initial) - это конечное число узлов, зараженных вредоносным ПО, во всей сети после прекращения распространения вредоносного ПО. Мы удалим ровно один узел из initial, полностью удалив его и все связи от этого узла к любому другому узлу. Верните узел, который, если его удалить, минимизирует M(initial). Если для минимизации M(initial) можно удалить несколько узлов, верните такой узел с наименьшим индексом.
Пример:
👨💻 Алгоритм:
1⃣ Создать множество для хранения уникальных обработанных адресов электронной почты.
2⃣ Для каждого адреса в emails:
Разделить адрес на локальное и доменное имя по символу '@'.
Обработать локальное имя:
Удалить все точки '.'.
Обрезать часть после символа '+'.
Объединить обработанное локальное имя и доменное имя.
Добавить результат в множество уникальных адресов.
3⃣ Вернуть количество уникальных адресов в множестве.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Вам дана сеть из n узлов, представленная в виде графа с матрицей смежности n x n, где i-й узел непосредственно связан с j-м узлом, если graph[i][j] == 1. Некоторые узлы изначально заражены вредоносным ПО. Если два узла соединены напрямую и хотя бы один из них заражен вредоносным ПО, то оба узла будут заражены вредоносным ПО. Такое распространение вредоносного ПО будет продолжаться до тех пор, пока больше не останется ни одного узла, зараженного таким образом. Предположим, что M(initial) - это конечное число узлов, зараженных вредоносным ПО, во всей сети после прекращения распространения вредоносного ПО. Мы удалим ровно один узел из initial, полностью удалив его и все связи от этого узла к любому другому узлу. Верните узел, который, если его удалить, минимизирует M(initial). Если для минимизации M(initial) можно удалить несколько узлов, верните такой узел с наименьшим индексом.
Пример:
Input: emails = ["[email protected]","[email protected]","[email protected]"]
Output: 2
Разделить адрес на локальное и доменное имя по символу '@'.
Обработать локальное имя:
Удалить все точки '.'.
Обрезать часть после символа '+'.
Объединить обработанное локальное имя и доменное имя.
Добавить результат в множество уникальных адресов.
class Solution {
func numUniqueEmails(_ emails: [String]) -> Int {
var uniqueEmails = Set<String>()
for email in emails {
let parts = email.split(separator: "@")
var local = parts[0].split(separator: "+")[0].replacingOccurrences(of: ".", with: "")
uniqueEmails.insert("\(local)@\(parts[1])")
}
return uniqueEmails.count
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 753. Cracking the Safe
Сложность: medium
Имеется сейф, защищенный паролем. Пароль представляет собой последовательность из n цифр, каждая из которых может находиться в диапазоне [0, k - 1]. Сейф имеет особый способ проверки пароля. Например, правильный пароль - "345", а вы вводите "012345": после ввода 0 последние 3 цифры - "0", что неверно. После ввода 1 последние 3 цифры - "01", что неверно. После ввода 2 последние 3 цифры - "012", что неверно.
После ввода 3 последние 3 цифры - "123", что неверно. После ввода 4 последние 3 цифры - "234", что неверно. После ввода 5 последние 3 цифры - "345", что верно, и сейф разблокируется. Верните любую строку минимальной длины, которая разблокирует сейф на определенном этапе ввода.
Пример:
👨💻 Алгоритм:
1⃣ Создайте граф, где каждая вершина представляет собой строку длины n-1, а каждое ребро между двумя вершинами представляет собой добавление одной из цифр из диапазона [0, k-1].
2⃣ Используйте алгоритм Эйлерова пути или цикла для нахождения пути, который проходит через каждое ребро ровно один раз.
3⃣ Составьте итоговую строку, которая включает начальную вершину и все добавленные цифры.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Имеется сейф, защищенный паролем. Пароль представляет собой последовательность из n цифр, каждая из которых может находиться в диапазоне [0, k - 1]. Сейф имеет особый способ проверки пароля. Например, правильный пароль - "345", а вы вводите "012345": после ввода 0 последние 3 цифры - "0", что неверно. После ввода 1 последние 3 цифры - "01", что неверно. После ввода 2 последние 3 цифры - "012", что неверно.
После ввода 3 последние 3 цифры - "123", что неверно. После ввода 4 последние 3 цифры - "234", что неверно. После ввода 5 последние 3 цифры - "345", что верно, и сейф разблокируется. Верните любую строку минимальной длины, которая разблокирует сейф на определенном этапе ввода.
Пример:
Input: n = 1, k = 2
Output: "10"
func crackSafe(_ n: Int, _ k: Int) -> String {
var seen = Set<String>()
var result = [Character]()
func dfs(_ node: String) {
for x in 0..<k {
let neighbor = node + String(x)
if !seen.contains(neighbor) {
seen.insert(neighbor)
dfs(String(neighbor.dropFirst()))
result.append(Character(String(x)))
}
}
}
let startNode = String(repeating: "0", count: n - 1)
dfs(startNode)
return startNode + String(result)
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 237. Delete Node in a Linked List
Сложность: medium
Дан односвязный список с головой head, и требуется удалить узел node в этом списке.
Вам дан узел node, который нужно удалить. У вас нет доступа к первому узлу head.
Все значения в односвязном списке уникальны, и гарантируется, что данный узел node не является последним узлом в списке.
Удалите данный узел. Обратите внимание, что под удалением узла мы не подразумеваем его удаление из памяти. Мы имеем в виду:
- Значение данного узла не должно существовать в односвязном списке.
- Количество узлов в односвязном списке должно уменьшиться на один.
- Все значения перед узлом должны оставаться в том же порядке.
- Все значения после узла должны оставаться в том же порядке.
Пример:
👨💻 Алгоритм:
1⃣ Копирование данных: Скопируйте значение из следующего узла (node.next) в текущий узел (node). Таким образом, текущий узел будет иметь значение, которое было в следующем узле.
2⃣ Обновление указателя: Обновите указатель next текущего узла, чтобы он ссылался на узел, следующий за узлом node.next. Это effectively удалит следующий узел из списка.
3⃣ Удаление ссылки на следующий узел: Убедитесь, что следующий узел больше не ссылается на другие узлы, тем самым полностью исключая его из списка.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан односвязный список с головой head, и требуется удалить узел node в этом списке.
Вам дан узел node, который нужно удалить. У вас нет доступа к первому узлу head.
Все значения в односвязном списке уникальны, и гарантируется, что данный узел node не является последним узлом в списке.
Удалите данный узел. Обратите внимание, что под удалением узла мы не подразумеваем его удаление из памяти. Мы имеем в виду:
- Значение данного узла не должно существовать в односвязном списке.
- Количество узлов в односвязном списке должно уменьшиться на один.
- Все значения перед узлом должны оставаться в том же порядке.
- Все значения после узла должны оставаться в том же порядке.
Пример:
Input: head = [4,5,1,9], node = 5
Output: [4,1,9]
Explanation: You are given the second node with value 5, the linked list should become 4 -> 1 -> 9 after calling your function.
class Solution {
func deleteNode(_ node: ListNode?) {
node?.val = node?.next?.val ?? 0
node?.next = node?.next?.next
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1229. Meeting Scheduler
Сложность: medium
Даны массивы доступных временных слотов slots1 и slots2 для двух человек и продолжительность встречи duration, верните самый ранний временной слот, который подходит обоим и имеет продолжительность duration.
Если нет общего временного слота, который удовлетворяет требованиям, верните пустой массив.
Формат временного слота — это массив из двух элементов [start, end], представляющий инклюзивный временной диапазон от start до end.
Гарантируется, что никакие два доступных временных слота одного и того же человека не пересекаются друг с другом. То есть для любых двух временных слотов [start1, end1] и [start2, end2] одного и того же человека либо start1 > end2, либо start2 > end1.
Пример:
👨💻 Алгоритм:
1⃣ Отсортируйте оба массива slots1 и slots2 по времени начала.
2⃣ Инициализируйте два указателя, указывающие на начало slots1 и slots2 соответственно.
3⃣ Перебирайте, пока указатель1 не достигнет конца slots1 или указатель2 не достигнет конца slots2:
Найдите общий слот между slots1[pointer1] и slots2[pointer2].
Если общий слот больше или равен duration, верните результат.
В противном случае найдите слот, который заканчивается раньше, и передвиньте указатель.
Если общий слот не найден, верните пустой массив.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Даны массивы доступных временных слотов slots1 и slots2 для двух человек и продолжительность встречи duration, верните самый ранний временной слот, который подходит обоим и имеет продолжительность duration.
Если нет общего временного слота, который удовлетворяет требованиям, верните пустой массив.
Формат временного слота — это массив из двух элементов [start, end], представляющий инклюзивный временной диапазон от start до end.
Гарантируется, что никакие два доступных временных слота одного и того же человека не пересекаются друг с другом. То есть для любых двух временных слотов [start1, end1] и [start2, end2] одного и того же человека либо start1 > end2, либо start2 > end1.
Пример:
Input: slots1 = [[10,50],[60,120],[140,210]], slots2 = [[0,15],[60,70]], duration = 8
Output: [60,68]
Найдите общий слот между slots1[pointer1] и slots2[pointer2].
Если общий слот больше или равен duration, верните результат.
В противном случае найдите слот, который заканчивается раньше, и передвиньте указатель.
Если общий слот не найден, верните пустой массив.
class Solution {
func minAvailableDuration(_ slots1: [[Int]], _ slots2: [[Int]], _ duration: Int) -> [Int] {
let slots1 = slots1.sorted { $0[0] < $1[0] }
let slots2 = slots2.sorted { $0[0] < $1[0] }
var pointer1 = 0
var pointer2 = 0
while pointer1 < slots1.count && pointer2 < slots2.count {
let intersectLeft = max(slots1[pointer1][0], slots2[pointer2][0])
let intersectRight = min(slots1[pointer1][1], slots2[pointer2][1])
if intersectRight - intersectLeft >= duration {
return [intersectLeft, intersectLeft + duration]
}
if slots1[pointer1][1] < slots2[pointer2][1] {
pointer1 += 1
} else {
pointer2 += 1
}
}
return []
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 225. Implement Stack using Queues
Сложность: easy
Реализуйте стек (последним пришел - первым вышел, LIFO) с использованием только двух очередей. Реализованный стек должен поддерживать все функции обычного стека (push, top, pop и empty).
Реализуйте класс MyStack:
void push(int x): Добавляет элемент x на вершину стека.
int pop(): Удаляет элемент с вершины стека и возвращает его.
int top(): Возвращает элемент на вершине стека.
boolean empty(): Возвращает true, если стек пуст, иначе false.
Примечания:
Вы должны использовать только стандартные операции очереди, что означает, что допустимы только операции добавления в конец, просмотр/удаление из начала, определение размера и проверка на пустоту.
Пример:
👨💻 Алгоритм:
1⃣ Реализация методов push и pop:
Метод push добавляет элемент x в очередь q2, затем перемещает все элементы из q1 в q2 и меняет местами q1 и q2.
Метод pop удаляет элемент из q1 и обновляет значение top.
2⃣ Реализация методов top и empty:
Метод top возвращает верхний элемент стека.
Метод empty проверяет, пуста ли очередь q1, и возвращает соответствующее значение.
3⃣ Поддержка стандартных операций очереди:
Используйте только стандартные операции очереди: добавление в конец, удаление из начала, определение размера и проверка на пустоту.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Реализуйте стек (последним пришел - первым вышел, LIFO) с использованием только двух очередей. Реализованный стек должен поддерживать все функции обычного стека (push, top, pop и empty).
Реализуйте класс MyStack:
void push(int x): Добавляет элемент x на вершину стека.
int pop(): Удаляет элемент с вершины стека и возвращает его.
int top(): Возвращает элемент на вершине стека.
boolean empty(): Возвращает true, если стек пуст, иначе false.
Примечания:
Вы должны использовать только стандартные операции очереди, что означает, что допустимы только операции добавления в конец, просмотр/удаление из начала, определение размера и проверка на пустоту.
Пример:
Input
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
Output
[null, null, null, 2, 2, false]
Explanation
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // return 2
myStack.pop(); // return 2
myStack.empty(); // return False
Метод push добавляет элемент x в очередь q2, затем перемещает все элементы из q1 в q2 и меняет местами q1 и q2.
Метод pop удаляет элемент из q1 и обновляет значение top.
Метод top возвращает верхний элемент стека.
Метод empty проверяет, пуста ли очередь q1, и возвращает соответствующее значение.
Используйте только стандартные операции очереди: добавление в конец, удаление из начала, определение размера и проверка на пустоту.
class MyStack {
private var q1 = [Int]()
private var q2 = [Int]()
private var topElement: Int = 0
func push(_ x: Int) {
q2.append(x)
topElement = x
while !q1.isEmpty {
q2.append(q1.removeFirst())
}
(q1, q2) = (q2, q1)
}
func pop() {
q1.removeFirst()
if !q1.isEmpty {
topElement = q1.first!
}
}
func empty() -> Bool {
return q1.isEmpty
}
func top() -> Int {
return topElement
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 417. Pacific Atlantic Water Flow
Сложность: medium
Имеется прямоугольный остров размером m x n, который граничит с Тихим и Атлантическим океанами. Тихий океан касается левого и верхнего краев острова, а Атлантический океан - правого и нижнего краев. Остров разбит на сетку квадратных ячеек. Вам дана целочисленная матрица heights размером m x n, где heights[r][c] - высота над уровнем моря клетки с координатами (r, c). На острове выпадает много осадков, и дождевая вода может стекать в соседние клетки прямо на север, юг, восток и запад, если высота соседней клетки меньше или равна высоте текущей клетки. Вода может течь из любой клетки, прилегающей к океану, в океан. Верните двумерный список координат сетки result, где result[i] = [ri, ci] означает, что дождевая вода может течь из клетки (ri, ci) как в Тихий, так и в Атлантический океаны.
Пример:
👨💻 Алгоритм:
1⃣ Определите две матрицы для отслеживания клеток, из которых вода может течь в Тихий и Атлантический океаны, используя поиск в глубину (DFS) или поиск в ширину (BFS), начиная с границ, примыкающих к каждому океану.
2⃣ Выполните поиск для каждого океана, обновляя матрицы достижимости.
3⃣ Соберите координаты клеток, которые могут стекать в оба океана, проверяя пересечение двух матриц достижимости.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Имеется прямоугольный остров размером m x n, который граничит с Тихим и Атлантическим океанами. Тихий океан касается левого и верхнего краев острова, а Атлантический океан - правого и нижнего краев. Остров разбит на сетку квадратных ячеек. Вам дана целочисленная матрица heights размером m x n, где heights[r][c] - высота над уровнем моря клетки с координатами (r, c). На острове выпадает много осадков, и дождевая вода может стекать в соседние клетки прямо на север, юг, восток и запад, если высота соседней клетки меньше или равна высоте текущей клетки. Вода может течь из любой клетки, прилегающей к океану, в океан. Верните двумерный список координат сетки result, где result[i] = [ri, ci] означает, что дождевая вода может течь из клетки (ri, ci) как в Тихий, так и в Атлантический океаны.
Пример:
Input: heights = [[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]
Output: [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]
func pacificAtlantic(_ heights: [[Int]]) -> [[Int]] {
let m = heights.count
let n = heights[0].count
var pacific = Array(repeating: Array(repeating: false, count: n), count: m)
var atlantic = Array(repeating: Array(repeating: false, count: n), count: m)
let directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
func dfs(_ r: Int, _ c: Int, _ ocean: inout [[Bool]]) {
ocean[r][c] = true
for (dr, dc) in directions {
let nr = r + dr, nc = c + dc
if nr >= 0, nc >= 0, nr < m, nc < n, !ocean[nr][nc], heights[nr][nc] >= heights[r][c] {
dfs(nr, nc, &ocean)
}
}
}
for i in 0..<m {
dfs(i, 0, &pacific)
dfs(i, n - 1, &atlantic)
}
for j in 0..<n {
dfs(0, j, &pacific)
dfs(m - 1, j, &atlantic)
}
var result = [[Int]]()
for i in 0..<m {
for j in 0..<n {
if pacific[i][j] && atlantic[i][j] {
result.append([i, j])
}
}
}
return result
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 752. Open the Lock
Сложность: medium
Перед вами замок с 4 круглыми колесами. Каждое колесо имеет 10 слотов: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'. Колеса могут свободно вращаться и оборачиваться: например, мы можем повернуть "9" так, чтобы получился "0", или "0" так, чтобы получился "9". Каждый ход состоит из поворота одного колеса на один слот. Изначально замок начинается с '0000', строки, представляющей состояние 4 колес. Вам дан список тупиков, то есть если замок отобразит любой из этих кодов, колеса замка перестанут вращаться, и вы не сможете его открыть. Учитывая цель, представляющую значение колес, которое позволит отпереть замок, верните минимальное общее количество оборотов, необходимое для открытия замка, или -1, если это невозможно.
Пример:
👨💻 Алгоритм:
1⃣ Используйте алгоритм BFS для поиска кратчайшего пути от начального состояния '0000' до целевого состояния, избегая тупиков. Инициализируйте очередь с начальным состоянием '0000' и начальным шагом 0. Используйте множество для отслеживания посещенных состояний, чтобы избежать повторного посещения одного и того же состояния.
2⃣ Для каждого состояния в очереди: Проверьте все возможные переходы на следующий шаг, вращая каждое колесо на +1 и -1. Если найденное состояние является целевым, верните количество шагов. Если найденное состояние не является тупиком и не было посещено ранее, добавьте его в очередь и отметьте как посещенное.
3⃣ Если очередь пуста и целевое состояние не найдено, верните -1.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Перед вами замок с 4 круглыми колесами. Каждое колесо имеет 10 слотов: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'. Колеса могут свободно вращаться и оборачиваться: например, мы можем повернуть "9" так, чтобы получился "0", или "0" так, чтобы получился "9". Каждый ход состоит из поворота одного колеса на один слот. Изначально замок начинается с '0000', строки, представляющей состояние 4 колес. Вам дан список тупиков, то есть если замок отобразит любой из этих кодов, колеса замка перестанут вращаться, и вы не сможете его открыть. Учитывая цель, представляющую значение колес, которое позволит отпереть замок, верните минимальное общее количество оборотов, необходимое для открытия замка, или -1, если это невозможно.
Пример:
Input: deadends = ["0201","0101","0102","1212","2002"], target = "0202"
Output: 6
func openLock(_ deadends: [String], _ target: String) -> Int {
func neighbors(_ node: String) -> [String] {
var res = [String]()
let nodeArray = Array(node)
for i in 0..<4 {
var nodeChars = nodeArray
let x = Int(String(nodeChars[i]))!
for d in [-1, 1] {
let y = (x + d + 10) % 10
nodeChars[i] = Character(String(y))
res.append(String(nodeChars))
}
}
return res
}
let dead = Set(deadends)
var queue = [(String, Int)]()
queue.append(("0000", 0))
var visited = Set<String>()
visited.insert("0000")
while !queue.isEmpty {
let (node, steps) = queue.removeFirst()
if node == target {
return steps
}
if dead.contains(node) {
continue
}
for neighbor in neighbors(node) {
if !visited.contains(neighbor) {
visited.insert(neighbor)
queue.append((neighbor, steps + 1))
}
}
}
return -1
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 34. Find First and Last Position of Element in Sorted Array
Сложность: medium
Дан массив целых чисел nums, отсортированный в неубывающем порядке, найдите начальную и конечную позицию заданного целевого значения.
Если целевое значение не найдено в массиве, верните [-1, -1].
Вы должны написать алгоритм со временной сложностью O(log n).
Пример:
👨💻 Алгоритм:
1⃣ Определите функцию под названием findBound, которая принимает три аргумента: массив, целевое значение для поиска и булевое значение isFirst, указывающее, ищем ли мы первое или последнее вхождение цели.
Мы используем 2 переменные для отслеживания подмассива, который мы сканируем. Назовем их begin и end. Изначально begin устанавливается в 0, а end — в последний индекс массива.
2⃣ Мы итерируем, пока begin не станет больше, чем end.
На каждом шаге мы вычисляем средний элемент mid = (begin + end) / 2. Мы используем значение среднего элемента, чтобы решить, какую половину массива нам нужно искать.
Если nums[mid] == target:
Если isFirst true — это означает, что мы пытаемся найти первое вхождение элемента. Если mid == begin или nums[mid - 1] != target, тогда мы возвращаем mid как первое вхождение цели. В противном случае мы обновляем end = mid - 1.
Если isFirst false — это означает, что мы пытаемся найти последнее вхождение элемента. Если mid == end или nums[mid + 1] != target, тогда мы возвращаем mid как последнее вхождение цели. В противном случае мы обновляем begin = mid + 1.
3⃣ Если nums[mid] > target — мы обновляем end = mid - 1, так как мы должны отбросить правую сторону массива, поскольку средний элемент больше цели.
Если nums[mid] < target — мы обновляем begin = mid + 1, так как мы должны отбросить левую сторону массива, поскольку средний элемент меньше цели.
В конце нашей функции мы возвращаем значение -1, что указывает на то, что цель не найдена в массиве.
В основной функции searchRange мы сначала вызываем findBound с isFirst, установленным в true. Если это значение равно -1, мы можем просто вернуть [-1, -1]. В противном случае мы вызываем findBound с isFirst, установленным в false, чтобы получить последнее вхождение, а затем возвращаем результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив целых чисел nums, отсортированный в неубывающем порядке, найдите начальную и конечную позицию заданного целевого значения.
Если целевое значение не найдено в массиве, верните [-1, -1].
Вы должны написать алгоритм со временной сложностью O(log n).
Пример:
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Мы используем 2 переменные для отслеживания подмассива, который мы сканируем. Назовем их begin и end. Изначально begin устанавливается в 0, а end — в последний индекс массива.
На каждом шаге мы вычисляем средний элемент mid = (begin + end) / 2. Мы используем значение среднего элемента, чтобы решить, какую половину массива нам нужно искать.
Если nums[mid] == target:
Если isFirst true — это означает, что мы пытаемся найти первое вхождение элемента. Если mid == begin или nums[mid - 1] != target, тогда мы возвращаем mid как первое вхождение цели. В противном случае мы обновляем end = mid - 1.
Если isFirst false — это означает, что мы пытаемся найти последнее вхождение элемента. Если mid == end или nums[mid + 1] != target, тогда мы возвращаем mid как последнее вхождение цели. В противном случае мы обновляем begin = mid + 1.
Если nums[mid] < target — мы обновляем begin = mid + 1, так как мы должны отбросить левую сторону массива, поскольку средний элемент меньше цели.
В конце нашей функции мы возвращаем значение -1, что указывает на то, что цель не найдена в массиве.
В основной функции searchRange мы сначала вызываем findBound с isFirst, установленным в true. Если это значение равно -1, мы можем просто вернуть [-1, -1]. В противном случае мы вызываем findBound с isFirst, установленным в false, чтобы получить последнее вхождение, а затем возвращаем результат.
func searchRange(_ nums: [Int], _ target: Int) -> [Int] {
let firstOccurrence = findBound(nums, target, true)
if firstOccurrence == -1 {
return [-1, -1]
}
let lastOccurrence = findBound(nums, target, false)
return [firstOccurrence, lastOccurrence]
}
func findBound(_ nums: [Int], _ target: Int, _ isFirst: Bool) -> Int {
let N = nums.count
var begin = 0
var end = N - 1
while begin <= end {
let mid = (begin + end) / 2
if nums[mid] == target {
if isFirst {
if mid == begin || nums[mid - 1] != target {
return mid
}
end = mid - 1
} else {
if mid == end || nums[mid + 1] != target {
return mid
}
begin = mid + 1
}
} else if nums[mid] > target {
end = mid - 1
} else {
begin = mid + 1
}
}
return -1
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 945. Minimum Increment to Make Array Unique
Сложность: medium
Вам дан целочисленный массив nums. За один ход вы можете выбрать индекс i, где 0 <= i < nums.length, и увеличить nums[i] на 1. Верните минимальное количество ходов, чтобы каждое значение в nums было уникальным. Тестовые примеры генерируются так, чтобы ответ умещался в 32-битное целое число.
Пример:
👨💻 Алгоритм:
1⃣ Отсортировать массив nums.
Инициализировать переменную moves для подсчета количества ходов.
2⃣ Пройти по массиву и для каждого элемента, начиная со второго:
Если текущий элемент меньше или равен предыдущему элементу, увеличить текущий элемент до значения предыдущего элемента + 1 и обновить счетчик ходов.
3⃣ Вернуть общее количество ходов.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан целочисленный массив nums. За один ход вы можете выбрать индекс i, где 0 <= i < nums.length, и увеличить nums[i] на 1. Верните минимальное количество ходов, чтобы каждое значение в nums было уникальным. Тестовые примеры генерируются так, чтобы ответ умещался в 32-битное целое число.
Пример:
Input: nums = [1,2,2]
Output: 1
Инициализировать переменную moves для подсчета количества ходов.
Если текущий элемент меньше или равен предыдущему элементу, увеличить текущий элемент до значения предыдущего элемента + 1 и обновить счетчик ходов.
class Solution {
func minIncrementForUnique(_ nums: [Int]) -> Int {
var nums = nums.sorted()
var moves = 0
for i in 1..<nums.count {
if nums[i] <= nums[i - 1] {
moves += nums[i - 1] + 1 - nums[i]
nums[i] = nums[i - 1] + 1
}
}
return moves
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 330. Patching Array
Сложность: hard
Дан отсортированный массив целых чисел nums и целое число n. Добавьте/дополните элементы в массив таким образом, чтобы любое число в диапазоне [1, n] включительно могло быть сформировано как сумма некоторых элементов массива.
Верните минимальное количество дополнений, необходимых для этого.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация переменных:
Создайте переменную miss, представляющую наименьшее пропущенное число, которое еще не покрыто, и установите ее значение на 1. Создайте переменную patches для подсчета необходимых дополнений и переменную i для итерации по массиву nums.
2⃣ Основной цикл:
Используйте цикл while, который будет выполняться до тех пор, пока miss не станет больше n.
Внутри цикла проверьте, покрывает ли текущий элемент nums[i] значение miss. Если да, добавьте nums[i] к miss и увеличьте i. Если нет, добавьте значение miss к самому себе (это означает добавление нового элемента в массив) и увеличьте счетчик patches.
3⃣ Возврат результата:
После завершения цикла верните значение patches, которое представляет минимальное количество необходимых дополнений.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дан отсортированный массив целых чисел nums и целое число n. Добавьте/дополните элементы в массив таким образом, чтобы любое число в диапазоне [1, n] включительно могло быть сформировано как сумма некоторых элементов массива.
Верните минимальное количество дополнений, необходимых для этого.
Пример:
Input: nums = [1,3], n = 6
Output: 1
Explanation:
Combinations of nums are [1], [3], [1,3], which form possible sums of: 1, 3, 4.
Now if we add/patch 2 to nums, the combinations are: [1], [2], [3], [1,3], [2,3], [1,2,3].
Possible sums are 1, 2, 3, 4, 5, 6, which now covers the range [1, 6].
So we only need 1 patch.
Создайте переменную miss, представляющую наименьшее пропущенное число, которое еще не покрыто, и установите ее значение на 1. Создайте переменную patches для подсчета необходимых дополнений и переменную i для итерации по массиву nums.
Используйте цикл while, который будет выполняться до тех пор, пока miss не станет больше n.
Внутри цикла проверьте, покрывает ли текущий элемент nums[i] значение miss. Если да, добавьте nums[i] к miss и увеличьте i. Если нет, добавьте значение miss к самому себе (это означает добавление нового элемента в массив) и увеличьте счетчик patches.
После завершения цикла верните значение patches, которое представляет минимальное количество необходимых дополнений.
class Solution {
func minPatches(_ nums: [Int], _ n: Int) -> Int {
var patches = 0
var i = 0
var miss: Int64 = 1
while miss <= n {
if i < nums.count && nums[i] <= miss {
miss += Int64(nums[i])
i += 1
} else {
miss += miss
patches += 1
}
}
return patches
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM