Задача: 80. Remove Duplicates from Sorted Array II
Сложность: medium
Дан массив целых чисел nums, отсортированный в неубывающем порядке. Удалите из него некоторые дубликаты на месте так, чтобы каждый уникальный элемент встречался не более двух раз. Относительный порядок элементов должен быть сохранён.
Поскольку в некоторых языках программирования невозможно изменить длину массива, результат следует разместить в первой части массива nums. Более формально, если после удаления дубликатов остаётся k элементов, то первые k элементов массива nums должны содержать итоговый результат. Не важно, что остаётся за пределами первых k элементов.
Верните k после размещения итогового результата в первые k слотов массива nums.
Не выделяйте дополнительное пространство для другого массива. Вы должны сделать это, изменяя исходный массив на месте с использованием дополнительной памяти O(1).
Пример:
👨💻 Алгоритм:
1⃣ Инициализация переменных: Используйте две переменные: i, которая указывает на текущий индекс в массиве, и count, которая отслеживает количество каждого элемента. Начните обработку массива с первого элемента (индекс 1), предполагая, что первый элемент всегда имеет count равный 1.
2⃣ Обработка элементов массива: Для каждого элемента в массиве:
3⃣ Если текущий элемент такой же, как предыдущий (nums[i] == nums[i - 1]), увеличьте count.
Если count больше 2, это означает, что текущий элемент встречается более двух раз. В этом случае удалите этот элемент из массива с помощью операции удаления, поддерживаемой вашим языком программирования (например, del, pop, remove), и уменьшите индекс i на 1, чтобы корректно обработать следующий элемент.
Если текущий элемент отличается от предыдущего (nums[i] != nums[i - 1]), это означает начало новой последовательности, поэтому сбросьте count к 1.
Возвращение результата: После обработки всех элементов в массиве, все ненужные дубликаты удалены, и в массиве остаются только допустимые элементы. Верните длину обработанного массива, так как это количество элементов, которые теперь соответствуют условиям задачи.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив целых чисел nums, отсортированный в неубывающем порядке. Удалите из него некоторые дубликаты на месте так, чтобы каждый уникальный элемент встречался не более двух раз. Относительный порядок элементов должен быть сохранён.
Поскольку в некоторых языках программирования невозможно изменить длину массива, результат следует разместить в первой части массива nums. Более формально, если после удаления дубликатов остаётся k элементов, то первые k элементов массива nums должны содержать итоговый результат. Не важно, что остаётся за пределами первых k элементов.
Верните k после размещения итогового результата в первые k слотов массива nums.
Не выделяйте дополнительное пространство для другого массива. Вы должны сделать это, изменяя исходный массив на месте с использованием дополнительной памяти O(1).
Пример:
Input: nums = [1,1,1,2,2,3]
Output: 5, nums = [1,1,2,2,3,_]
Explanation: Your function should return k = 5, with the first five elements of nums being 1, 1, 2, 2 and 3 respectively.
It does not matter what you leave beyond the returned k (hence they are underscores).
Если count больше 2, это означает, что текущий элемент встречается более двух раз. В этом случае удалите этот элемент из массива с помощью операции удаления, поддерживаемой вашим языком программирования (например, del, pop, remove), и уменьшите индекс i на 1, чтобы корректно обработать следующий элемент.
Если текущий элемент отличается от предыдущего (nums[i] != nums[i - 1]), это означает начало новой последовательности, поэтому сбросьте count к 1.
Возвращение результата: После обработки всех элементов в массиве, все ненужные дубликаты удалены, и в массиве остаются только допустимые элементы. Верните длину обработанного массива, так как это количество элементов, которые теперь соответствуют условиям задачи.
func removeDuplicates(_ nums: inout [Int]) -> Int {
var j = 0
for i in 0..<nums.count {
if j < 2 || nums[i] > nums[j - 2] {
nums[j] = nums[i]
j += 1
}
}
return j
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1277. Count Square Submatrices with All Ones
Сложность: medium
Если задана матрица m * n из единиц и нулей, верните, сколько квадратных подматриц имеют все единицы.
Пример:
👨💻 Алгоритм:
1⃣ Создайте вспомогательную матрицу dp таких же размеров, что и исходная матрица, для хранения размеров максимальных квадратов.
2⃣ Пройдите по каждому элементу матрицы и обновите dp следующим образом: если элемент равен 1, то dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1.
3⃣ Суммируйте все значения в dp, чтобы получить количество квадратных подматриц, состоящих из всех единиц.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Если задана матрица m * n из единиц и нулей, верните, сколько квадратных подматриц имеют все единицы.
Пример:
Input: matrix =
[
[0,1,1,1],
[1,1,1,1],
[0,1,1,1]
]
Output: 15
class Solution {
func countSquares(_ matrix: [[Int]]) -> Int {
let m = matrix.count, n = matrix[0].count
var dp = Array(repeating: Array(repeating: 0, count: n), count: m)
var count = 0
for i in 0..<m {
for j in 0..<n {
if matrix[i][j] == 1 {
if i == 0 || j == 0 {
dp[i][j] = 1
} else {
dp[i][j] = min(dp[i-1][j], min(dp[i][j-1], dp[i-1][j-1])) + 1
}
count += dp[i][j]
}
}
}
return count
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1425. Constrained Subsequence Sum
Сложность: hard
Дан целочисленный массив nums и целое число k, верните максимальную сумму непустой подпоследовательности этого массива, такую, что для любых двух последовательных целых чисел в подпоследовательности nums[i] и nums[j], где i < j, выполняется условие j - i <= k.
Подпоследовательность массива получается путем удаления некоторого количества элементов (может быть ноль) из массива, оставляя оставшиеся элементы в их исходном порядке.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте очередь queue и массив dp той же длины, что и nums.
2⃣ Итерируйте i по индексам nums:
Если i минус первый элемент queue больше k, удалите элемент из начала queue.
Установите dp[i] как dp[queue.front()] + nums[i]. Если queue пуст, используйте 0 вместо dp[queue.front()].
Пока dp[queue.back()] меньше dp[i], удаляйте элементы с конца queue.
Если dp[i] > 0, добавьте i в конец queue.
3⃣ Верните максимальное значение в массиве dp.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дан целочисленный массив nums и целое число k, верните максимальную сумму непустой подпоследовательности этого массива, такую, что для любых двух последовательных целых чисел в подпоследовательности nums[i] и nums[j], где i < j, выполняется условие j - i <= k.
Подпоследовательность массива получается путем удаления некоторого количества элементов (может быть ноль) из массива, оставляя оставшиеся элементы в их исходном порядке.
Пример:
Input: nums = [10,2,-10,5,20], k = 2
Output: 37
Explanation: The subsequence is [10, 2, 5, 20].
Если i минус первый элемент queue больше k, удалите элемент из начала queue.
Установите dp[i] как dp[queue.front()] + nums[i]. Если queue пуст, используйте 0 вместо dp[queue.front()].
Пока dp[queue.back()] меньше dp[i], удаляйте элементы с конца queue.
Если dp[i] > 0, добавьте i в конец queue.
class Solution {
func constrainedSubsetSum(_ nums: [Int], _ k: Int) -> Int {
var queue = [Int]()
var dp = [Int](repeating: 0, count: nums.count)
var maxSum = Int.min
for i in 0..<nums.count {
if !queue.isEmpty && i - queue.first! > k {
queue.removeFirst()
}
dp[i] = (!queue.isEmpty ? dp[queue.first!] : 0) + nums[i]
while !queue.isEmpty && dp[queue.last!] < dp[i] {
queue.removeLast()
}
if dp[i] > 0 {
queue.append(i)
}
maxSum = max(maxSum, dp[i])
}
return maxSum
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 344. Reverse String
Сложность: easy
Напишите функцию, которая переворачивает строку. Входная строка представлена в виде массива символов s.
Вы должны сделать это, изменяя входной массив на месте с использованием O(1) дополнительной памяти.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация указателей:
Установите два указателя: один на начало массива (left), другой на конец массива (right).
2⃣ Перестановка символов:
Пока левый указатель меньше правого, обменяйте символы, на которые указывают левый и правый указатели.
Сдвиньте левый указатель вправо, а правый указатель влево.
3⃣ Завершение работы:
Повторяйте шаг 2 до тех пор, пока левый указатель не станет больше или равен правому.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Напишите функцию, которая переворачивает строку. Входная строка представлена в виде массива символов s.
Вы должны сделать это, изменяя входной массив на месте с использованием O(1) дополнительной памяти.
Пример:
Input: s = ["h","e","l","l","o"]
Output: ["o","l","l","e","h"]
Установите два указателя: один на начало массива (left), другой на конец массива (right).
Пока левый указатель меньше правого, обменяйте символы, на которые указывают левый и правый указатели.
Сдвиньте левый указатель вправо, а правый указатель влево.
Повторяйте шаг 2 до тех пор, пока левый указатель не станет больше или равен правому.
class Solution {
func reverseString(_ s: inout [Character]) {
var left = 0
var right = s.count - 1
while left < right {
s.swapAt(left, right)
left += 1
right -= 1
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 121. Best Time to Buy and Sell Stock
Сложность: easy
Вам дан массив цен, где prices[i] является ценой данной акции в i-й день.
Нужно выбрать день для покупки и день в будущем для продажи, чтобы получить максимальную прибыль. Если прибыли нет — вернуть 0.
Пример:
👨💻 Алгоритм:
1⃣ Поддерживаем переменную
2⃣ Вычисляем потенциальную прибыль на каждом шаге и обновляем
3⃣ Возвращаем максимальную прибыль после прохода по массиву
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Вам дан массив цен, где prices[i] является ценой данной акции в i-й день.
Нужно выбрать день для покупки и день в будущем для продажи, чтобы получить максимальную прибыль. Если прибыли нет — вернуть 0.
Пример:
Input: prices = [7,1,5,3,6,4] Output: 5 minPrice, обновляем её при каждом снижении ценыmaxProfitclass Solution {
func maxProfit(_ prices: [Int]) -> Int {
var minPrice = Int.max
var maxProfit = 0
for price in prices {
if price < minPrice {
minPrice = price
} else if price - minPrice > maxProfit {
maxProfit = price - minPrice
}
}
return maxProfit
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 416. Partition Equal Subset Sum
Сложность: medium
Если задан целочисленный массив nums, верните третье максимальное число в этом массиве. Если третьего максимального числа не существует, верните максимальное число.
Пример:
👨💻 Алгоритм:
1⃣ Проверьте, является ли сумма всех элементов массива четной. Если нет, верните false.
2⃣ Используйте динамическое программирование для определения, можно ли найти подмножество с суммой, равной половине от общей суммы элементов.
3⃣ Инициализируйте массив для хранения возможных сумм и обновляйте его, проверяя каждое число в массиве.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Если задан целочисленный массив nums, верните третье максимальное число в этом массиве. Если третьего максимального числа не существует, верните максимальное число.
Пример:
Input: nums = [1,5,11,5]
Output: true
func canPartition(_ nums: [Int]) -> Bool {
let sum = nums.reduce(0, +)
if sum % 2 != 0 { return false }
let target = sum / 2
var dp = [Bool](repeating: false, count: target + 1)
dp[0] = true
for num in nums {
for j in stride(from: target, through: num, by: -1) {
dp[j] = dp[j] || dp[j - num]
}
}
return dp[target]
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 69. Sqrt(x)
Сложность: easy
Дано неотрицательное целое число x. Верните квадратный корень из x, округлённый вниз до ближайшего целого числа. Возвращаемое целое число также должно быть неотрицательным.
Вы не должны использовать встроенные функции или операторы для возведения в степень.
Например, не следует использовать pow(x, 0.5) в C++ или x ** 0.5 в Python.
Пример:
👨💻 Алгоритм:
1⃣ Если x < 2, верните x. Установите левую границу left = 2 и правую границу right = x / 2.
2⃣ Пока left ≤ right:
Возьмите num = (left + right) / 2 в качестве предположения. Вычислите num × num и сравните его с x:
Если num × num > x, переместите правую границу right = pivot − 1.
В противном случае, если num × num < x, переместите левую границу left = pivot + 1.
В противном случае num × num == x, целочисленный квадратный корень найден, давайте вернем его.
3⃣ Верните right.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дано неотрицательное целое число x. Верните квадратный корень из x, округлённый вниз до ближайшего целого числа. Возвращаемое целое число также должно быть неотрицательным.
Вы не должны использовать встроенные функции или операторы для возведения в степень.
Например, не следует использовать pow(x, 0.5) в C++ или x ** 0.5 в Python.
Пример:
Input: x = 4
Output: 2
Explanation: The square root of 4 is 2, so we return 2.
Возьмите num = (left + right) / 2 в качестве предположения. Вычислите num × num и сравните его с x:
Если num × num > x, переместите правую границу right = pivot − 1.
В противном случае, если num × num < x, переместите левую границу left = pivot + 1.
В противном случае num × num == x, целочисленный квадратный корень найден, давайте вернем его.
func mySqrt(_ x: Int) -> Int {
if x < 2 { return x }
var left = 2
var right = x / 2
while left <= right {
let pivot = left + (right - left) / 2
let num = pivot * pivot
if num > x {
right = pivot - 1
} else if num < x {
left = pivot + 1
} else {
return pivot
}
}
return right
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 515. Largest Value in Each Tree Row
Сложность: medium
Дан корень двоичного дерева, верните массив наибольших значений в каждой строке дерева (индексация с 0).
Пример:
👨💻 Алгоритм:
1⃣ Если корень дерева равен null (пустое дерево), верните пустой список. Инициализируйте список ans для хранения результатов и очередь с корнем дерева для выполнения поиска в ширину (BFS).
2⃣ Выполните BFS, пока очередь не пуста: инициализируйте currMax минимальным значением и сохраните длину очереди в currentLength. Повторите currentLength раз: удалите узел из очереди, обновите currMax, если значение узла больше. Для каждого дочернего узла, если он не равен null, добавьте его в очередь.
3⃣ Добавьте currMax в ans. Верните ans.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан корень двоичного дерева, верните массив наибольших значений в каждой строке дерева (индексация с 0).
Пример:
Input: root = [1,3,2,5,3,null,9]
Output: [1,3,9]
class Solution {
func largestValues(_ root: TreeNode?) -> [Int] {
guard let root = root else { return [] }
var ans = [Int]()
var queue = [root]
while !queue.isEmpty {
var currentLength = queue.count
var currMax = Int.min
for _ in 0..<currentLength {
let node = queue.removeFirst()
currMax = max(currMax, node.val)
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
ans.append(currMax)
}
return ans
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 743. Network Delay Time
Сложность: medium
Дана сеть из узлов, помеченных от 1 до n. Также дано times - список времен прохождения сигнала в виде направленных ребер times[i] = (ui, vi, wi), где ui - исходный узел, vi - целевой узел, а wi - время прохождения сигнала от источника до цели. Мы пошлем сигнал из заданного узла k. Верните минимальное время, которое потребуется всем узлам, чтобы получить сигнал. Если все узлы не могут получить сигнал, верните -1.
Пример:
👨💻 Алгоритм:
1⃣ Представьте граф в виде списка смежности.
2⃣ Используйте алгоритм Дейкстры для нахождения кратчайших путей от узла k до всех других узлов.
3⃣ Найдите максимальное значение среди кратчайших путей к узлам. Если какой-либо узел недостижим, верните -1.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дана сеть из узлов, помеченных от 1 до n. Также дано times - список времен прохождения сигнала в виде направленных ребер times[i] = (ui, vi, wi), где ui - исходный узел, vi - целевой узел, а wi - время прохождения сигнала от источника до цели. Мы пошлем сигнал из заданного узла k. Верните минимальное время, которое потребуется всем узлам, чтобы получить сигнал. Если все узлы не могут получить сигнал, верните -1.
Пример:
Input: times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
Output: 2
import Foundation
func networkDelayTime(_ times: [[Int]], _ n: Int, _ k: Int) -> Int {
var graph = [Int: [(Int, Int)]]()
for i in 1...n {
graph[i] = []
}
for time in times {
graph[time[0]]?.append((time[1], time[2]))
}
var minHeap = [(0, k)]
var minTime = [Int: Int]()
for i in 1...n {
minTime[i] = Int.max
}
minTime[k] = 0
while !minHeap.isEmpty {
minHeap.sort { $0.0 < $1.0 }
let (time, node) = minHeap.removeFirst()
if let neighbors = graph[node] {
for (neighbor, t) in neighbors {
let newTime = time + t
if newTime < minTime[neighbor]! {
minTime[neighbor] = newTime
minHeap.append((newTime, neighbor))
}
}
}
}
let maxTime = minTime.values.max()!
return maxTime == Int.max ? -1 : maxTime
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 561. Array Partition
Сложность: easy
Дан массив целых чисел nums из 2n элементов. Разделите эти числа на n пар (a1, b1), (a2, b2), ..., (an, bn) так, чтобы сумма min(ai, bi) для всех i была максимальной. Верните максимальную сумму.
Пример:
👨💻 Алгоритм:
1⃣ Отсортируйте массив nums в неубывающем порядке.
2⃣ Итерируйте через массив, выбирая каждый второй элемент (начиная с первого).
3⃣ Суммируйте выбранные элементы и верните эту сумму.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дан массив целых чисел nums из 2n элементов. Разделите эти числа на n пар (a1, b1), (a2, b2), ..., (an, bn) так, чтобы сумма min(ai, bi) для всех i была максимальной. Верните максимальную сумму.
Пример:
Input: nums = [1,4,3,2]
Output: 4
Explanation: All possible pairings (ignoring the ordering of elements) are:
1. (1, 4), (2, 3) -> min(1, 4) + min(2, 3) = 1 + 2 = 3
2. (1, 3), (2, 4) -> min(1, 3) + min(2, 4) = 1 + 2 = 3
3. (1, 2), (3, 4) -> min(1, 2) + min(3, 4) = 1 + 3 = 4
So the maximum possible sum is 4.
class Solution {
func arrayPairSum(_ nums: [Int]) -> Int {
let sortedNums = nums.sorted()
var sum = 0
for i in stride(from: 0, to: sortedNums.count, by: 2) {
sum += sortedNums[i]
}
return sum
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1498. Number of Subsequences That Satisfy the Given Sum Condition
Сложность: medium
Вам дан массив целых чисел
Верните количество непустых подпоследовательностей массива
Пример:
👨💻 Алгоритм:
1⃣ Инициализация и подготовка:
Инициализируйте переменные answer равным 0 и n как длину массива nums.
Отсортируйте массив nums.
Подготовьте массив power для хранения степеней двойки до n по модулю 10^9+7.
2⃣ Итерация и бинарный поиск:
Для каждого индекса left от 0 до n - 1 выполните бинарный поиск, чтобы найти самый правый индекс right, где nums[right] <= target - nums[left].
Если left <= right, добавьте количество допустимых подпоследовательностей к answer.
3⃣ Возврат результата:
Верните answer по модулю 10^9+7.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан массив целых чисел
nums и целое число target.Верните количество непустых подпоследовательностей массива
nums, таких что сумма минимального и максимального элемента в них меньше или равна target. Так как ответ может быть слишком большим, верните его по модулю 10^9 + 7.Пример:
Input: nums = [3,5,6,7], target = 9
Output: 4
Explanation: There are 4 subsequences that satisfy the condition.
[3] -> Min value + max value <= target (3 + 3 <= 9)
[3,5] -> (3 + 5 <= 9)
[3,5,6] -> (3 + 6 <= 9)
[3,6] -> (3 + 6 <= 9)
Инициализируйте переменные answer равным 0 и n как длину массива nums.
Отсортируйте массив nums.
Подготовьте массив power для хранения степеней двойки до n по модулю 10^9+7.
Для каждого индекса left от 0 до n - 1 выполните бинарный поиск, чтобы найти самый правый индекс right, где nums[right] <= target - nums[left].
Если left <= right, добавьте количество допустимых подпоследовательностей к answer.
Верните answer по модулю 10^9+7.
class Solution {
func numSubseq(_ nums: [Int], _ target: Int) -> Int {
let mod = 1_000_000_007
let n = nums.count
var nums = nums.sorted()
var power = [Int](repeating: 1, count: n)
for i in 1..<n {
power[i] = (power[i - 1] * 2) % mod
}
var answer = 0
var left = 0
var right = n - 1
while left <= right {
if nums[left] + nums[right] <= target {
answer = (answer + power[right - left]) % mod
left += 1
} else {
right -= 1
}
}
return answer
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 901. Online Stock Span
Сложность: medium
Разработайте алгоритм, который собирает ежедневные котировки цен на некоторые акции и возвращает размах цены этой акции за текущий день. Размах цены акции за один день - это максимальное количество дней подряд (начиная с этого дня и в обратном направлении), в течение которых цена акции была меньше или равна цене этого дня.
Например, если цены акции за последние четыре дня равны [7,2,1,2], а цена акции сегодня равна 2, то размах сегодняшнего дня равен 4, поскольку, начиная с сегодняшнего дня, цена акции была меньше или равна 2 в течение 4 дней подряд.
Также, если цена акции за последние четыре дня равна [7,34,1,2], а цена акции сегодня равна 8, то размах сегодняшнего дня равен 3, так как начиная с сегодняшнего дня цена акции была меньше или равна 8 в течение 3 дней подряд. Реализация класса StockSpanner: StockSpanner() Инициализирует объект класса. int next(int price) Возвращает размах цены акции, учитывая, что сегодняшняя цена равна price.
Пример:
👨💻 Алгоритм:
1⃣ Инициализировать стек для хранения пар значений (цена, размах) и переменную для текущего индекса.
2⃣ Для метода next:
Установить начальный размах текущего дня равным 1.
Пока стек не пуст и верхний элемент стека имеет цену меньше или равную текущей цене:
Добавить размах верхнего элемента стека к текущему размаху.
Удалить верхний элемент стека.
3⃣ Добавить текущую цену и размах на вершину стека.
Вернуть текущий размах.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Разработайте алгоритм, который собирает ежедневные котировки цен на некоторые акции и возвращает размах цены этой акции за текущий день. Размах цены акции за один день - это максимальное количество дней подряд (начиная с этого дня и в обратном направлении), в течение которых цена акции была меньше или равна цене этого дня.
Например, если цены акции за последние четыре дня равны [7,2,1,2], а цена акции сегодня равна 2, то размах сегодняшнего дня равен 4, поскольку, начиная с сегодняшнего дня, цена акции была меньше или равна 2 в течение 4 дней подряд.
Также, если цена акции за последние четыре дня равна [7,34,1,2], а цена акции сегодня равна 8, то размах сегодняшнего дня равен 3, так как начиная с сегодняшнего дня цена акции была меньше или равна 8 в течение 3 дней подряд. Реализация класса StockSpanner: StockSpanner() Инициализирует объект класса. int next(int price) Возвращает размах цены акции, учитывая, что сегодняшняя цена равна price.
Пример:
Input
["StockSpanner", "next", "next", "next", "next", "next", "next", "next"]
[[], [100], [80], [60], [70], [60], [75], [85]]
Output
[null, 1, 1, 1, 2, 1, 4, 6]
Установить начальный размах текущего дня равным 1.
Пока стек не пуст и верхний элемент стека имеет цену меньше или равную текущей цене:
Добавить размах верхнего элемента стека к текущему размаху.
Удалить верхний элемент стека.
Вернуть текущий размах.
class StockSpanner {
private var stack: [(Int, Int)] = []
func next(_ price: Int) -> Int {
var span = 1
while let last = stack.last, last.0 <= price {
span += last.1
stack.removeLast()
}
stack.append((price, span))
return span
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1514. Path with Maximum Probability
Сложность: medium
Вам дан неориентированный взвешенный граф из n узлов (индексация с нуля), представленный списком ребер, где edges[i] = [a, b] является неориентированным ребром, соединяющим узлы a и b с вероятностью успешного прохождения этого ребра succProb[i].
Даны два узла start и end, найдите путь с максимальной вероятностью успеха, чтобы перейти от start к end, и верните его вероятность успеха.
Если пути от start до end не существует, верните 0. Ваш ответ будет принят, если он отличается от правильного ответа не более чем на 1e-5.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте массив maxProb как максимальную вероятность достижения каждого узла из начального узла, установите maxProb[start] равным 1.
2⃣ Расслабьте все ребра: для каждого ребра (u, v), если найдена более высокая вероятность достижения u через это ребро, обновите max_prob[u] как max_prob[u] = max_prob[v] * path_prob. Если найдена более высокая вероятность достижения v через это ребро, обновите max_prob[v].
3⃣ Если нам не удается обновить какой-либо узел с более высокой вероятностью, мы можем остановить итерацию, перейдя к шагу 4. В противном случае повторяйте шаг 2, пока все ребра не будут расслаблены n - 1 раз.
Верните max_prob[end].
😎 Решение
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан неориентированный взвешенный граф из n узлов (индексация с нуля), представленный списком ребер, где edges[i] = [a, b] является неориентированным ребром, соединяющим узлы a и b с вероятностью успешного прохождения этого ребра succProb[i].
Даны два узла start и end, найдите путь с максимальной вероятностью успеха, чтобы перейти от start к end, и верните его вероятность успеха.
Если пути от start до end не существует, верните 0. Ваш ответ будет принят, если он отличается от правильного ответа не более чем на 1e-5.
Пример:
Input: n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.2], start = 0, end = 2
Output: 0.25000
Explanation: There are two paths from start to end, one having a probability of success = 0.2 and the other has 0.5 * 0.5 = 0.25.
Верните max_prob[end].
class Solution {
func maxProbability(_ n: Int, _ edges: [[Int]], _ succProb: [Double], _ start: Int, _ end: Int) -> Double {
var maxProb = [Double](repeating: 0, count: n)
maxProb[start] = 1.0
for _ in 0..<n-1 {
var hasUpdate = false
for j in 0..<edges.count {
let u = edges[j][0]
let v = edges[j][1]
let pathProb = succProb[j]
if maxProb[u] * pathProb > maxProb[v] {
maxProb[v] = maxProb[u] * pathProb
hasUpdate = true
}
if maxProb[v] * pathProb > maxProb[u] {
maxProb[u] = maxProb[v] * pathProb
hasUpdate = true
}
}
if !hasUpdate {
break
}
}
return maxProb[end]
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 295. Find Median from Data Stream
Сложность: hard
Медиана — это среднее значение в упорядоченном списке целых чисел. Если размер списка четный, то медианы нет, и медиана — это среднее арифметическое двух средних значений.
Например, для arr = [2, 3, 4] медиана равна 3.
Например, для arr = [2, 3] медиана равна (2 + 3) / 2 = 2.5.
Реализуйте класс MedianFinder:
MedianFinder() инициализирует объект MedianFinder.
void addNum(int num) добавляет целое число num из потока данных в структуру данных.
double findMedian() возвращает медиану всех элементов на данный момент. Ответы с точностью до 10^-5 от фактического ответа будут приниматься.
Пример:
👨💻 Алгоритм:
1⃣ Храните числа в контейнере с возможностью изменения размера:
Создайте массив для хранения чисел.
2⃣ Добавление нового числа:
Добавьте новое число в массив.
3⃣ Вычисление и вывод медианы:
Отсортируйте массив.
Если размер массива нечетный, верните среднее значение массива.
Если размер массива четный, верните среднее арифметическое двух средних значений массива.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Медиана — это среднее значение в упорядоченном списке целых чисел. Если размер списка четный, то медианы нет, и медиана — это среднее арифметическое двух средних значений.
Например, для arr = [2, 3, 4] медиана равна 3.
Например, для arr = [2, 3] медиана равна (2 + 3) / 2 = 2.5.
Реализуйте класс MedianFinder:
MedianFinder() инициализирует объект MedianFinder.
void addNum(int num) добавляет целое число num из потока данных в структуру данных.
double findMedian() возвращает медиану всех элементов на данный момент. Ответы с точностью до 10^-5 от фактического ответа будут приниматься.
Пример:
Input
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
Output
[null, null, null, 1.5, null, 2.0]
Explanation
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1); // arr = [1]
medianFinder.addNum(2); // arr = [1, 2]
medianFinder.findMedian(); // return 1.5 (i.e., (1 + 2) / 2)
medianFinder.addNum(3); // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0
Создайте массив для хранения чисел.
Добавьте новое число в массив.
Отсортируйте массив.
Если размер массива нечетный, верните среднее значение массива.
Если размер массива четный, верните среднее арифметическое двух средних значений массива.
class MedianFinder {
private var numbers: [Int] = []
func addNum(_ num: Int) {
numbers.append(num)
}
func findMedian() -> Double {
numbers.sort()
let n = numbers.count
if n % 2 == 0 {
return Double(numbers[n / 2 - 1] + numbers[n / 2]) / 2.0
} else {
return Double(numbers[n / 2])
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 214. Shortest Palindrome
Сложность: hard
Дана строка s. Вы можете преобразовать s в палиндром, добавив символы в начало строки.
Верните самый короткий палиндром, который можно получить, выполняя это преобразование.
Пример:
👨💻 Алгоритм:
1⃣ Создание обратной строки:
Создаем обратную строку rev от исходной строки s.
2⃣ Итерация для поиска наибольшего палиндрома:
Перемещаемся по индексу i от 0 до n - 1.
Проверяем, является ли подстрока s от 0 до n - i равной подстроке rev от i до конца строки.
Если находим такое совпадение, возвращаем обратную подстроку от начала rev до i + исходная строка s.
3⃣ Возврат результата:
Возвращаем наименьший палиндром, полученный путем добавления символов в начало строки s.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дана строка s. Вы можете преобразовать s в палиндром, добавив символы в начало строки.
Верните самый короткий палиндром, который можно получить, выполняя это преобразование.
Пример:
Input: s = "aacecaaa"
Output: "aaacecaaa"
Создаем обратную строку rev от исходной строки s.
Перемещаемся по индексу i от 0 до n - 1.
Проверяем, является ли подстрока s от 0 до n - i равной подстроке rev от i до конца строки.
Если находим такое совпадение, возвращаем обратную подстроку от начала rev до i + исходная строка s.
Возвращаем наименьший палиндром, полученный путем добавления символов в начало строки s.
class Solution {
func shortestPalindrome(_ s: String) -> String {
let n = s.count
let rev = String(s.reversed())
for i in 0..<n {
let startIndex = s.index(s.startIndex, offsetBy: 0)
let endIndex = s.index(s.startIndex, offsetBy: n - i)
let revStartIndex = rev.index(rev.startIndex, offsetBy: i)
let revEndIndex = rev.endIndex
if s[startIndex..<endIndex] == rev[revStartIndex..<revEndIndex] {
let prefix = rev[rev.startIndex..<revStartIndex]
return prefix + s
}
}
return ""
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1022. Sum of Root To Leaf Binary Numbers
Сложность: easy
Вам дан корень двоичного дерева, в котором каждый узел имеет значение 0 или 1. Каждый путь от корня к листьям представляет собой двоичное число, начиная со старшего бита. Например, если путь 0 -> 1 -> 1 -> 0 -> 1, то в двоичном виде это может представлять 01101, что равно 13. Для всех листьев дерева рассмотрите числа, представленные путем от корня к этому листу. Верните сумму этих чисел. Тестовые примеры генерируются таким образом, чтобы ответ помещался в 32-битовое целое число.
Пример:
👨💻 Алгоритм:
1⃣ Рекурсивный обход дерева:
Используйте функцию DFS (поиск в глубину) для обхода дерева, начиная от корня. Передавайте текущее значение числа по пути как параметр.
2⃣ Анализ текущего узла:
Если узел является листом (не имеет потомков), добавьте текущее значение числа к общей сумме.
Если узел не является листом, рекурсивно вызовите функцию DFS для левого и правого дочерних узлов, обновляя текущее значение числа.
3⃣ Возврат результата:
После завершения обхода верните общую сумму чисел, представленных путями от корня к листьям.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Вам дан корень двоичного дерева, в котором каждый узел имеет значение 0 или 1. Каждый путь от корня к листьям представляет собой двоичное число, начиная со старшего бита. Например, если путь 0 -> 1 -> 1 -> 0 -> 1, то в двоичном виде это может представлять 01101, что равно 13. Для всех листьев дерева рассмотрите числа, представленные путем от корня к этому листу. Верните сумму этих чисел. Тестовые примеры генерируются таким образом, чтобы ответ помещался в 32-битовое целое число.
Пример:
Input: root = [1,0,1,0,1,0,1]
Output: 22
Используйте функцию DFS (поиск в глубину) для обхода дерева, начиная от корня. Передавайте текущее значение числа по пути как параметр.
Если узел является листом (не имеет потомков), добавьте текущее значение числа к общей сумме.
Если узел не является листом, рекурсивно вызовите функцию DFS для левого и правого дочерних узлов, обновляя текущее значение числа.
После завершения обхода верните общую сумму чисел, представленных путями от корня к листьям.
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 {
func sumRootToLeaf(_ root: TreeNode?) -> Int {
func dfs(_ node: TreeNode?, _ current_value: Int) -> Int {
guard let node = node else { return 0 }
let current_value = (current_value << 1) | node.val
if node.left == nil && node.right == nil {
return current_value
}
return dfs(node.left, current_value) + dfs(node.right, current_value)
}
return dfs(root, 0)
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 772. Basic Calculator III
Сложность: medium
Реализуйте базовый калькулятор для вычисления простого строкового выражения.
Строка выражения содержит только неотрицательные целые числа, операторы '+', '-', '*', '/' и открывающие '(' и закрывающие скобки ')'. Целочисленное деление должно округляться к нулю.
Предполагается, что данное выражение всегда корректно. Все промежуточные результаты будут находиться в диапазоне [-2^31, 2^31 - 1].
Примечание: нельзя использовать встроенные функции для вычисления строк как математических выражений, такие как eval().
Пример:
👨💻 Алгоритм:
1⃣ Определите вспомогательную функцию evaluate, которая принимает оператор и числовые аргументы. Заметьте, что эта функция идентична той, что представлена в подходе "Basic Calculator II". Инициализируйте несколько переменных: стек для хранения промежуточных результатов, curr для отслеживания текущего числа, которое мы строим, и previousOperator для отслеживания предыдущего оператора. Добавьте в строку s случайный символ, который не будет появляться во входных данных, например "@".
2⃣ Итерация по входным данным. Для каждого символа c: если c является цифрой, добавьте его к curr. В противном случае, если c == '(', мы начинаем вычисление нового изолированного выражения. В этом случае сохраните previousOperator в стек и установите previousOperator = "+".
3⃣ Если c является оператором, то необходимо вычислить значение curr. Используйте функцию evaluate, чтобы применить previousOperator к curr, и добавьте результат в стек. Затем сбросьте curr до нуля и обновите previousOperator = c. Если c == ')', это означает, что мы находимся в конце изолированного выражения и должны полностью его вычислить. Извлекайте из стека до тех пор, пока не достигнете оператора, суммируя все извлеченные числа в curr. Как только достигнете оператора, обновите previousOperator = stack.pop(). Верните сумму всех чисел в стеке.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Реализуйте базовый калькулятор для вычисления простого строкового выражения.
Строка выражения содержит только неотрицательные целые числа, операторы '+', '-', '*', '/' и открывающие '(' и закрывающие скобки ')'. Целочисленное деление должно округляться к нулю.
Предполагается, что данное выражение всегда корректно. Все промежуточные результаты будут находиться в диапазоне [-2^31, 2^31 - 1].
Примечание: нельзя использовать встроенные функции для вычисления строк как математических выражений, такие как eval().
Пример:
Input: s = "1+1"
Output: 2
class Solution {
private func evaluate(_ operator: Character, _ first: String, _ second: String) -> String {
let x = Int(first)!
let y = Int(second)!
var res = 0
switch operator {
case "+":
res = x
case "-":
res = -x
case "*":
res = x * y
default:
res = x / y
}
return String(res)
}
func calculate(_ s: String) -> Int {
var stack = [String]()
var curr = ""
var previousOperator: Character = "+"
let s = s + "@"
let operators: Set<Character> = ["+", "-", "*", "/"]
for c in s {
if c.isNumber {
curr += String(c)
} else if c == "(" {
stack.append(String(previousOperator))
previousOperator = "+"
} else {
if previousOperator == "*" || previousOperator == "/" {
stack.append(evaluate(previousOperator, stack.removeLast(), curr))
} else {
stack.append(evaluate(previousOperator, curr, "0"))
}
curr = ""
previousOperator = c
if c == ")" {
var currentTerm = 0
while !operators.contains(stack.last!) {
currentTerm += Int(stack.removeLast())!
}
curr = String(currentTerm)
previousOperator = stack.removeLast().first!
}
}
}
var ans = 0
for num in stack {
ans += Int(num)!
}
return ans
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 134. Gas Station
Сложность: medium
Вдоль кругового маршрута расположены n заправочных станций, на каждой из которых находится определённое количество топлива gas[i].
У вас есть автомобиль с неограниченным топливным баком, и для проезда от i-й станции к следующей (i + 1)-й станции требуется cost[i] топлива. Путешествие начинается с пустым баком на одной из заправочных станций.
Учитывая два массива целых чисел gas и cost, верните индекс начальной заправочной станции, если вы можете проехать вокруг цепи один раз по часовой стрелке, в противном случае верните -1. Если решение существует, оно гарантированно будет уникальным.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте переменные curr_gain, total_gain и answer значением 0.
2⃣ Пройдите по массивам gas и cost. Для каждого индекса i увеличивайте total_gain и curr_gain на gas[i] - cost[i].
Если curr_gain меньше 0, проверьте, может ли станция i + 1 быть начальной станцией: установите answer как i + 1, сбросьте curr_gain до 0 и повторите шаг 2.
3⃣ По завершении итерации, если total_gain меньше 0, верните -1. В противном случае верните answer.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вдоль кругового маршрута расположены n заправочных станций, на каждой из которых находится определённое количество топлива gas[i].
У вас есть автомобиль с неограниченным топливным баком, и для проезда от i-й станции к следующей (i + 1)-й станции требуется cost[i] топлива. Путешествие начинается с пустым баком на одной из заправочных станций.
Учитывая два массива целых чисел gas и cost, верните индекс начальной заправочной станции, если вы можете проехать вокруг цепи один раз по часовой стрелке, в противном случае верните -1. Если решение существует, оно гарантированно будет уникальным.
Пример:
Input: gas = [1,2,3,4,5], cost = [3,4,5,1,2]
Output: 3
Explanation:
Start at station 3 (index 3) and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 4. Your tank = 4 - 1 + 5 = 8
Travel to station 0. Your tank = 8 - 2 + 1 = 7
Travel to station 1. Your tank = 7 - 3 + 2 = 6
Travel to station 2. Your tank = 6 - 4 + 3 = 5
Travel to station 3. The cost is 5. Your gas is just enough to travel back to station 3.
Therefore, return 3 as the starting index.
Если curr_gain меньше 0, проверьте, может ли станция i + 1 быть начальной станцией: установите answer как i + 1, сбросьте curr_gain до 0 и повторите шаг 2.
func canCompleteCircuit(gas: [Int], cost: [Int]) -> Int {
var currGain = 0
var totalGain = 0
var answer = 0
for i in 0..<gas.count {
let gain = gas[i] - cost[i]
totalGain += gain
currGain += gain
if currGain < 0 {
answer = i + 1
currGain = 0
}
}
return totalGain >= 0 ? answer : -1
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 562. Longest Line of Consecutive One in Matrix
Сложность: medium
Дана бинарная матрица размера m x n. Вернуть длину самой длинной последовательной линии из единиц в матрице.
Линия может быть горизонтальной, вертикальной, диагональной или анти-диагональной.
Пример:
👨💻 Алгоритм:
1⃣ Создайте 3 матрицы для хранения текущей длины последовательных единиц: horizontal, vertical, diagonal и anti_diagonal.
2⃣ Итерируйте через каждый элемент матрицы: Если элемент равен 1, обновите соответствующие значения в матрицах horizontal, vertical, diagonal и anti_diagonal. Обновите максимальную длину последовательной линии.
3⃣ Верните максимальную длину.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дана бинарная матрица размера m x n. Вернуть длину самой длинной последовательной линии из единиц в матрице.
Линия может быть горизонтальной, вертикальной, диагональной или анти-диагональной.
Пример:
Input: mat = [[0,1,1,0],[0,1,1,0],[0,0,0,1]]
Output: 3
class Solution {
func longestLine(_ mat: [[Int]]) -> Int {
if mat.isEmpty || mat[0].isEmpty {
return 0
}
let m = mat.count
let n = mat[0].count
var maxLength = 0
var horizontal = Array(repeating: Array(repeating: 0, count: n), count: m)
var vertical = Array(repeating: Array(repeating: 0, count: n), count: m)
var diagonal = Array(repeating: Array(repeating: 0, count: n), count: m)
var antiDiagonal = Array(repeating: Array(repeating: 0, count: n), count: m)
for i in 0..<m {
for j in 0..<n {
if mat[i][j] == 1 {
horizontal[i][j] = (j > 0 ? horizontal[i][j-1] : 0) + 1
vertical[i][j] = (i > 0 ? vertical[i-1][j] : 0) + 1
diagonal[i][j] = (i > 0 && j > 0 ? diagonal[i-1][j-1] : 0) + 1
antiDiagonal[i][j] = (i > 0 && j < n - 1 ? antiDiagonal[i-1][j+1] : 0) + 1
maxLength = max(maxLength, horizontal[i][j], vertical[i][j], diagonal[i][j], antiDiagonal[i][j])
}
}
}
return maxLength
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 207. Course Schedule
Сложность: medium
Всего у вас есть numCourses курсов, которые нужно пройти, пронумерованных от 0 до numCourses - 1. Вам дан массив prerequisites, где prerequisites[i] = [ai, bi] указывает на то, что вы должны сначала пройти курс bi, если хотите взять курс ai.
Например, пара [0, 1] указывает на то, что для прохождения курса 0 сначала нужно пройти курс 1.
Верните true, если вы можете завершить все курсы. В противном случае верните false.
Пример:
👨💻 Алгоритм:
1⃣ Создайте массив indegree длины n, где indegree[x] хранит количество входящих рёбер в узел x. Создайте список смежности adj, в котором adj[x] содержит все узлы с входящим ребром от узла x, то есть соседей узла x. Создайте этот список смежности, итерируя prerequisites. Для каждого prerequisites добавьте ребро от prerequisites[1] к prerequisites[0] и увеличьте indegree prerequisites[0] на 1.
2⃣ Инициализируйте очередь целых чисел q и начните алгоритм BFS, перемещаясь от листовых узлов к родительским узлам. Начните обход BFS, поместив все листовые узлы (indegree равное 0) в очередь. Создайте целочисленную переменную nodesVisited = 0 для подсчета количества посещенных узлов.
3⃣ Пока очередь не пуста:
Извлеките первый узел из очереди.
Увеличьте nodesVisited на 1.
Для каждого соседа (узлы, которые имеют входящее ребро от узла) узла уменьшите indegree[neighbor] на 1, чтобы удалить ребро node -> neighbor.
Если indegree[neighbor] == 0, это означает, что neighbor ведет себя как листовой узел, поэтому добавьте neighbor в очередь.
Если количество посещенных узлов меньше общего количества узлов, то есть nodesVisited < n, верните false, так как должен быть цикл. В противном случае, если nodesVisited == numCourses, верните true. Можно сократить это до просто возвращения nodesVisited == numCourses.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Всего у вас есть numCourses курсов, которые нужно пройти, пронумерованных от 0 до numCourses - 1. Вам дан массив prerequisites, где prerequisites[i] = [ai, bi] указывает на то, что вы должны сначала пройти курс bi, если хотите взять курс ai.
Например, пара [0, 1] указывает на то, что для прохождения курса 0 сначала нужно пройти курс 1.
Верните true, если вы можете завершить все курсы. В противном случае верните false.
Пример:
Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.
Извлеките первый узел из очереди.
Увеличьте nodesVisited на 1.
Для каждого соседа (узлы, которые имеют входящее ребро от узла) узла уменьшите indegree[neighbor] на 1, чтобы удалить ребро node -> neighbor.
Если indegree[neighbor] == 0, это означает, что neighbor ведет себя как листовой узел, поэтому добавьте neighbor в очередь.
Если количество посещенных узлов меньше общего количества узлов, то есть nodesVisited < n, верните false, так как должен быть цикл. В противном случае, если nodesVisited == numCourses, верните true. Можно сократить это до просто возвращения nodesVisited == numCourses.
class Solution {
func canFinish(_ numCourses: Int, _ prerequisites: [[Int]]) -> Bool {
var indegree = [Int](repeating: 0, count: numCourses)
var adj = [[Int]](repeating: [Int](), count: numCourses)
for prerequisite in prerequisites {
adj[prerequisite[1]].append(prerequisite[0])
indegree[prerequisite[0]] += 1
}
var q = [Int]()
for i in 0..<numCourses {
if indegree[i] == 0 {
q.append(i)
}
}
var nodesVisited = 0
while !q.isEmpty {
let node = q.removeFirst()
nodesVisited += 1
for neighbor in adj[node] {
indegree[neighbor] -= 1
if indegree[neighbor] == 0 {
q.append(neighbor)
}
}
}
return nodesVisited == numCourses
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 23. Merge k Sorted Lists
Сложность: medium
Вам дан массив из k списков связанных списков, каждый связанный список отсортирован в порядке возрастания. Объедините все связанные списки в один отсортированный связанный список и верните его.
Пример:
👨💻 Алгоритм:
1⃣ Используем min-heap для хранения текущих головных узлов всех списков.
2⃣ Извлекаем минимальный элемент из кучи, добавляем его в результирующий список, вставляем следующий узел, если он есть.
3⃣ Повторяем, пока куча не пуста, возвращаем голову объединенного списка.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан массив из k списков связанных списков, каждый связанный список отсортирован в порядке возрастания. Объедините все связанные списки в один отсортированный связанный список и верните его.
Пример:
Input: lists = [[1,4,5],[1,3,4],[2,6]]
Output: [1,1,2,3,4,4,5,6]
class ListNode {
var val: Int
var next: ListNode?
init(_ val: Int) {
self.val = val
self.next = nil
}
}
func mergeKLists(_ lists: [ListNode?]) -> ListNode? {
var heap = [ListNode]()
for list in lists {
if let node = list {
heap.append(node)
}
}
heap.sort { $0.val < $1.val }
let dummy = ListNode(0)
var current: ListNode? = dummy
while !heap.isEmpty {
let smallest = heap.removeFirst()
current?.next = smallest
current = smallest
if let next = smallest.next {
var index = heap.firstIndex { $0.val > next.val } ?? heap.count
heap.insert(next, at: index)
}
}
return dummy.next
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM