Задача: 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
Задача: 64. Minimum Path Sum
Сложность: medium
На сетке размером m на n, заполненной неотрицательными числами, найдите путь от верхнего левого угла до нижнего правого, который минимизирует сумму всех чисел вдоль своего пути.
Примечание: Вы можете перемещаться только вниз или вправо в любой момент времени.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация дополнительной матрицы dp такого же размера, как и исходная матрица. В этой матрице dp(i, j) представляет минимальную сумму пути от индекса (i, j) до самого правого нижнего элемента. Начинаем с инициализации самого правого нижнего элемента dp как последнего элемента заданной матрицы.
2⃣ Для каждого элемента, начиная с правого нижнего угла, мы обходим матрицу в обратном порядке и заполняем её требуемыми минимальными суммами. Важно отметить, что на каждом элементе мы можем перемещаться либо вправо, либо вниз.
3⃣ Для заполнения минимальной суммы используется уравнение: dp(i, j) = grid(i, j) + min(dp(i+1, j), dp(i, j+1)), с учётом граничных условий.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
На сетке размером m на n, заполненной неотрицательными числами, найдите путь от верхнего левого угла до нижнего правого, который минимизирует сумму всех чисел вдоль своего пути.
Примечание: Вы можете перемещаться только вниз или вправо в любой момент времени.
Пример:
Input: grid = [[1,3,1],[1,5,1],[4,2,1]]
Output: 7
Explanation: Because the path 1 → 3 → 1 → 1 → 1 minimizes the sum.
func minPathSum(_ grid: [[Int]]) -> Int {
var dp = Array(repeating: Array(repeating: 0, count: grid[0].count), count: grid.count)
for i in stride(from: grid.count - 1, through: 0, by: -1) {
for j in stride(from: grid[0].count - 1, through: 0, by: -1) {
if i == grid.count - 1 && j != grid[0].count - 1 {
dp[i][j] = grid[i][j] + dp[i][j + 1]
} else if j == grid[0].count - 1 && i != grid.count - 1 {
dp[i][j] = grid[i][j] + dp[i + 1][j]
} else if j != grid[0].count - 1 && i != grid.count - 1 {
dp[i][j] = grid[i][j] + min(dp[i + 1][j], dp[i][j + 1])
} else {
dp[i][j] = grid[i][j]
}
}
}
return dp[0][0]
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 868. Binary Gap
Сложность: easy
Дано положительное целое число n, найдите и верните наибольшее расстояние между любыми двумя соседними единицами в двоичном представлении числа n. Если нет двух соседних единиц, верните 0.
Две единицы считаются соседними, если их разделяют только нули (возможно, никаких нулей нет). Расстояние между двумя единицами — это абсолютная разница между их позициями в битовом представлении. Например, две единицы в "1001" имеют расстояние 3.
Пример:
👨💻 Алгоритм:
1⃣ Создайте список A индексов i, таких что в двоичном представлении числа n i-й бит установлен в 1.
2⃣ Используйте список A, чтобы найти максимальное расстояние между соседними значениями. Для этого пройдите по списку и вычислите разницу между каждым соседним элементом.
3⃣ Верните найденное максимальное расстояние.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дано положительное целое число n, найдите и верните наибольшее расстояние между любыми двумя соседними единицами в двоичном представлении числа n. Если нет двух соседних единиц, верните 0.
Две единицы считаются соседними, если их разделяют только нули (возможно, никаких нулей нет). Расстояние между двумя единицами — это абсолютная разница между их позициями в битовом представлении. Например, две единицы в "1001" имеют расстояние 3.
Пример:
Input: n = 22
Output: 2
Explanation: 22 in binary is "10110".
The first adjacent pair of 1's is "10110" with a distance of 2.
The second adjacent pair of 1's is "10110" with a distance of 1.
The answer is the largest of these two distances, which is 2.
Note that "10110" is not a valid pair since there is a 1 separating the two 1's underlined.
class Solution {
func binaryGap(_ N: Int) -> Int {
var A = [Int]()
for i in 0..<32 where (N >> i) & 1 == 1 {
A.append(i)
}
var ans = 0
for i in 0..<A.count - 1 {
ans = max(ans, A[i + 1] - A[i])
}
return ans
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 510. Inorder Successor in BST II
Сложность: medium
Дан узел в двоичном дереве поиска, верните его последующего (in-order successor) в этом дереве. Если у узла нет последующего, верните null.
Последующий узла — это узел с наименьшим ключом, большим, чем node.val.
Вы будете иметь прямой доступ к узлу, но не к корню дерева. Каждый узел будет иметь ссылку на своего родителя. Ниже приведено определение для Node:
Пример:
👨💻 Алгоритм:
1⃣ Проверка правого поддерева
Если у узла есть правый потомок, перейдите к правому узлу, затем спускайтесь влево до самого нижнего узла. Этот узел будет следующим узлом в порядке in-order.
2⃣ Поиск предка
Если у узла нет правого потомка, поднимайтесь по дереву до тех пор, пока узел не станет левым потомком своего родителя. Родитель этого узла будет следующим узлом в порядке in-order.
3⃣ Возвращение результата
Верните найденный узел или null, если следующий узел не найден.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан узел в двоичном дереве поиска, верните его последующего (in-order successor) в этом дереве. Если у узла нет последующего, верните null.
Последующий узла — это узел с наименьшим ключом, большим, чем node.val.
Вы будете иметь прямой доступ к узлу, но не к корню дерева. Каждый узел будет иметь ссылку на своего родителя. Ниже приведено определение для Node:
class Node {
public int val;
public Node left;
public Node right;
public Node parent;
}Пример:
Input: tree = [5,3,6,2,4,null,null,1], node = 6
Output: null
Explanation: There is no in-order successor of the current node, so the answer is null.
Если у узла есть правый потомок, перейдите к правому узлу, затем спускайтесь влево до самого нижнего узла. Этот узел будет следующим узлом в порядке in-order.
Если у узла нет правого потомка, поднимайтесь по дереву до тех пор, пока узел не станет левым потомком своего родителя. Родитель этого узла будет следующим узлом в порядке in-order.
Верните найденный узел или null, если следующий узел не найден.
class Node {
var val: Int
var left: Node?
var right: Node?
var parent: Node?
init(_ val: Int) {
self.val = val
}
}
class Solution {
func inorderSuccessor(_ x: Node?) -> Node? {
var x = x
if let right = x?.right {
x = right
while let left = x?.left {
x = left
}
return x
}
while let parent = x?.parent, x === parent.right {
x = parent
}
return x?.parent
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1055. Shortest Way to Form String
Сложность: medium
Подпоследовательность строки - это новая строка, которая образуется из исходной строки путем удаления некоторых (можно ни одного) символов без нарушения взаимного расположения оставшихся символов. (например, "ace" является подпоследовательностью "abcde", а "aec" - нет). Если даны две строки source и target, верните минимальное количество подпоследовательностей source, чтобы их объединение равнялось target. Если задача невыполнима, верните -1.
Пример:
👨💻 Алгоритм:
1⃣ Используй два указателя для отслеживания текущих позиций в строках source и target.
2⃣ Перебирай символы строки source, пока не найдешь совпадающий символ в target.
Если ты прошел всю строку source и не нашел все символы target, увеличь счетчик количества подпоследовательностей и начни снова с начала source.
3⃣ Повтори шаги 2 и 3 до тех пор, пока не пройдешь всю строку target.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Подпоследовательность строки - это новая строка, которая образуется из исходной строки путем удаления некоторых (можно ни одного) символов без нарушения взаимного расположения оставшихся символов. (например, "ace" является подпоследовательностью "abcde", а "aec" - нет). Если даны две строки source и target, верните минимальное количество подпоследовательностей source, чтобы их объединение равнялось target. Если задача невыполнима, верните -1.
Пример:
Input: source = "abc", target = "abcbc"
Output: 2
Если ты прошел всю строку source и не нашел все символы target, увеличь счетчик количества подпоследовательностей и начни снова с начала source.
func minSubsequences(_ source: String, _ target: String) -> Int {
let sourceArray = Array(source)
let targetArray = Array(target)
var subsequencesCount = 0
var targetIndex = 0
while targetIndex < targetArray.count {
var sourceIndex = 0
subsequencesCount += 1
let startIndex = targetIndex
while sourceIndex < sourceArray.count && targetIndex < targetArray.count {
if sourceArray[sourceIndex] == targetArray[targetIndex] {
targetIndex += 1
}
sourceIndex += 1
}
if targetIndex == startIndex {
return -1
}
}
return subsequencesCount
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1095. Find in Mountain Array
Сложность: hard
Массив arr является горным массивом тогда и только тогда, когда:
Длина массива arr >= 3.
Существует некоторое i с 0 < i < arr.length - 1 такое, что:
arr[0] < arr[1] < ... < arr[i - 1] < arr[i]
arr[i] > arr[i + 1] > ... > arr[arr.length - 1]
Дан горный массив mountainArr, верните минимальный индекс, такой что mountainArr.get(index) == target. Если такого индекса не существует, верните -1.
Вы не можете напрямую обращаться к массиву. Вы можете использовать интерфейс MountainArray:
MountainArray.get(k) возвращает элемент массива на индексе k (индексация начинается с 0).
MountainArray.length() возвращает длину массива.
Решения, использующие более 100 вызовов MountainArray.get, будут оценены как неправильные. Также любые решения, которые пытаются обойти ограничение, будут дисквалифицированы.
Пример:
👨💻 Алгоритм:
1⃣ Найти индекс пика: Инициализируем два указателя low и high, где low начинается с 1, а high — с длины массива минус 2. Используем бинарный поиск для нахождения пикового элемента: если элемент в середине меньше следующего элемента, то пиковый элемент находится справа, иначе он находится слева. Продолжаем сужать диапазон поиска до тех пор, пока low не станет равным high. Это и будет индекс пика.
2⃣ Бинарный поиск в возрастающей части массива: Устанавливаем указатели low и high для поиска в диапазоне от 0 до пикового индекса. Проводим обычный бинарный поиск: если значение в середине меньше целевого значения, перемещаем low вправо, иначе перемещаем high влево. По завершении поиска проверяем, равно ли значение по индексу low целевому значению. Если да, возвращаем индекс, иначе продолжаем.
3⃣ Бинарный поиск в убывающей части массива: Устанавливаем указатели low и high для поиска в диапазоне от пикового индекса плюс 1 до конца массива. Проводим бинарный поиск, но с учетом убывающей последовательности: если значение в середине больше целевого значения, перемещаем low вправо, иначе перемещаем high влево. По завершении поиска проверяем, равно ли значение по индексу low целевому значению. Если да, возвращаем индекс. Если значение не найдено, возвращаем -1.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Массив arr является горным массивом тогда и только тогда, когда:
Длина массива arr >= 3.
Существует некоторое i с 0 < i < arr.length - 1 такое, что:
arr[0] < arr[1] < ... < arr[i - 1] < arr[i]
arr[i] > arr[i + 1] > ... > arr[arr.length - 1]
Дан горный массив mountainArr, верните минимальный индекс, такой что mountainArr.get(index) == target. Если такого индекса не существует, верните -1.
Вы не можете напрямую обращаться к массиву. Вы можете использовать интерфейс MountainArray:
MountainArray.get(k) возвращает элемент массива на индексе k (индексация начинается с 0).
MountainArray.length() возвращает длину массива.
Решения, использующие более 100 вызовов MountainArray.get, будут оценены как неправильные. Также любые решения, которые пытаются обойти ограничение, будут дисквалифицированы.
Пример:
Input: array = [1,2,3,4,5,3,1], target = 3
Output: 2
Explanation: 3 exists in the array, at index=2 and index=5. Return the minimum index, which is 2.
class Solution {
func findInMountainArray(_ target: Int, _ mountainArr: MountainArray) -> Int {
let length = mountainArr.length()
var low = 1
var high = length - 2
while low != high {
let mid = (low + high) / 2
if mountainArr.get(mid) < mountainArr.get(mid + 1) {
low = mid + 1
} else {
high = mid
}
}
let peak = low
low = 0
high = peak
while low < high {
let mid = (low + high) / 2
if mountainArr.get(mid) < target {
low = mid + 1
} else {
high = mid
}
}
if mountainArr.get(low) == target {
return low
}
low = peak + 1
high = length - 1
while low < high {
let mid = (low + high) / 2
if mountainArr.get(mid) > target {
low = mid + 1
} else {
high = mid
}
}
if mountainArr.get(low) == target {
return low
}
return -1
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 530. Minimum Absolute Difference in BST
Сложность: easy
Дано корень бинарного дерева поиска (BST), верните минимальную абсолютную разницу между значениями любых двух разных узлов в дереве.
Пример:
👨💻 Алгоритм:
1⃣ Обход дерева в порядке возрастания (инфиксный обход):
Создайте список inorderNodes для хранения значений узлов.
Выполните инфиксный обход дерева, добавляя значения узлов в список.
2⃣ Нахождение минимальной разницы:
Создайте переменную minDifference и инициализируйте её бесконечностью.
Пройдите по списку inorderNodes, начиная с индекса 1, и найдите минимальную абсолютную разницу между последовательными элементами.
3⃣ Возврат результата:
Верните minDifference.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дано корень бинарного дерева поиска (BST), верните минимальную абсолютную разницу между значениями любых двух разных узлов в дереве.
Пример:
Input: root = [4,2,6,1,3]
Output: 1
Создайте список inorderNodes для хранения значений узлов.
Выполните инфиксный обход дерева, добавляя значения узлов в список.
Создайте переменную minDifference и инициализируйте её бесконечностью.
Пройдите по списку inorderNodes, начиная с индекса 1, и найдите минимальную абсолютную разницу между последовательными элементами.
Верните minDifference.
class Solution {
private var inorderNodes: [Int] = []
func getMinimumDifference(_ root: TreeNode?) -> Int {
inorderTraversal(root)
var minDifference = Int.max
for i in 1..<inorderNodes.count {
minDifference = min(minDifference, inorderNodes[i] - inorderNodes[i - 1])
}
return minDifference
}
private func inorderTraversal(_ node: TreeNode?) {
guard let node = node else { return }
inorderTraversal(node.left)
inorderNodes.append(node.val)
inorderTraversal(node.right)
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1135. Connecting Cities With Minimum Cost
Сложность: medium
Есть n городов, пронумерованных от 1 до n. Вам даны целое число n и массив connections, где connections[i] = [xi, yi, costi] указывает, что стоимость соединения города xi и города yi (двунаправленное соединение) равна costi.
Верните минимальную стоимость для соединения всех n городов так, чтобы между каждой парой городов был хотя бы один путь. Если невозможно соединить все n городов, верните -1.
Стоимость - это сумма использованных стоимостей соединений.
Пример:
👨💻 Алгоритм:
1⃣ Сортировка рёбер:
Отсортируйте все соединения (рёбра) в графе по их весам (стоимости) в порядке возрастания.
2⃣ Итерация по рёбрам и объединение:
Используйте структуру данных Disjoint Set (Union-Find) для проверки циклов и объединения поддеревьев. Для каждого ребра проверьте, принадлежат ли его концы разным поддеревьям, и если да, объедините их, добавив ребро в минимальное остовное дерево (MST).
3⃣ Проверка соединённости:
Подсчитайте количество рёбер в MST. Если оно меньше n-1, верните -1, так как соединить все города невозможно. Иначе верните суммарную стоимость рёбер в MST.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Есть n городов, пронумерованных от 1 до n. Вам даны целое число n и массив connections, где connections[i] = [xi, yi, costi] указывает, что стоимость соединения города xi и города yi (двунаправленное соединение) равна costi.
Верните минимальную стоимость для соединения всех n городов так, чтобы между каждой парой городов был хотя бы один путь. Если невозможно соединить все n городов, верните -1.
Стоимость - это сумма использованных стоимостей соединений.
Пример:
Input: n = 3, connections = [[1,2,5],[1,3,6],[2,3,1]]
Output: 6
Explanation: Choosing any 2 edges will connect all cities so we choose the minimum 2.
Отсортируйте все соединения (рёбра) в графе по их весам (стоимости) в порядке возрастания.
Используйте структуру данных Disjoint Set (Union-Find) для проверки циклов и объединения поддеревьев. Для каждого ребра проверьте, принадлежат ли его концы разным поддеревьям, и если да, объедините их, добавив ребро в минимальное остовное дерево (MST).
Подсчитайте количество рёбер в MST. Если оно меньше n-1, верните -1, так как соединить все города невозможно. Иначе верните суммарную стоимость рёбер в MST.
class DisjointSet {
private var parent: [Int]
init(_ n: Int) {
parent = Array(0...n)
}
func find(_ x: Int) -> Int {
if parent[x] != x {
parent[x] = find(parent[x])
}
return parent[x]
}
func union(_ x: Int, _ y: Int) {
let rootX = find(x)
let rootY = find(y)
if rootX != rootY {
parent[rootY] = rootX
}
}
}
class Solution {
func minimumCost(_ n: Int, _ connections: [[Int]]) -> Int {
let sortedConnections = connections.sorted { $0[2] < $1[2] }
let disjointSet = DisjointSet(n)
var totalCost = 0
var edgesUsed = 0
for connection in sortedConnections {
let x = connection[0]
let y = connection[1]
let cost = connection[2]
if disjointSet.find(x) != disjointSet.find(y) {
disjointSet.union(x, y)
totalCost += cost
edgesUsed += 1
if edgesUsed == n - 1 {
return totalCost
}
}
}
return edgesUsed == n - 1 ? totalCost : -1
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 341. Flatten Nested List Iterator
Сложность: medium
Вам дан вложенный список целых чисел nestedList. Каждый элемент либо является целым числом, либо списком, элементы которого также могут быть целыми числами или другими списками. Реализуйте итератор для его развёртки.
Реализуйте класс NestedIterator:
NestedIterator(List<NestedInteger> nestedList) Инициализирует итератор вложенным списком nestedList.
int next() Возвращает следующий целый элемент вложенного списка.
boolean hasNext() Возвращает true, если в вложенном списке еще остались целые числа, и false в противном случае.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация
Сохраняйте исходный вложенный список в стеке или очереди. Используйте стек для сохранения состояния итерации по вложенным спискам.
2⃣ Метод next()
Возвращает следующий целый элемент из стека или очереди. Если текущий элемент является списком, развёртывайте его и добавляйте элементы в стек.
3⃣ Метод hasNext()
Проверяет, есть ли в стеке или очереди оставшиеся целые элементы. Если на вершине стека находится список, развёртывайте его до тех пор, пока не встретится целый элемент.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан вложенный список целых чисел nestedList. Каждый элемент либо является целым числом, либо списком, элементы которого также могут быть целыми числами или другими списками. Реализуйте итератор для его развёртки.
Реализуйте класс NestedIterator:
NestedIterator(List<NestedInteger> nestedList) Инициализирует итератор вложенным списком nestedList.
int next() Возвращает следующий целый элемент вложенного списка.
boolean hasNext() Возвращает true, если в вложенном списке еще остались целые числа, и false в противном случае.
Пример:
Input: nestedList = [[1,1],2,[1,1]]
Output: [1,1,2,1,1]
Explanation: By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,1,2,1,1].
Сохраняйте исходный вложенный список в стеке или очереди. Используйте стек для сохранения состояния итерации по вложенным спискам.
Возвращает следующий целый элемент из стека или очереди. Если текущий элемент является списком, развёртывайте его и добавляйте элементы в стек.
Проверяет, есть ли в стеке или очереди оставшиеся целые элементы. Если на вершине стека находится список, развёртывайте его до тех пор, пока не встретится целый элемент.
class NestedIterator {
private var stack: [NestedInteger] = []
init(_ nestedList: [NestedInteger]) {
self.flatten(nestedList)
}
private func flatten(_ nestedList: [NestedInteger]) {
for ni in nestedList.reversed() {
stack.append(ni)
}
}
func next() -> Int {
return stack.removeLast().getInteger()
}
func hasNext() -> Bool {
while !stack.isEmpty, !stack.last!.isInteger() {
flatten(stack.removeLast().getList())
}
return !stack.isEmpty
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1016. Binary String With Substrings Representing 1 To N
Сложность: medium
Если задана двоичная строка s и положительное целое число n, верните true, если двоичное представление всех целых чисел в диапазоне [1, n] является подстрокой s, или false в противном случае. Подстрока - это непрерывная последовательность символов в строке.
Пример:
👨💻 Алгоритм:
1⃣ Генерация двоичных строк:
Для каждого числа в диапазоне [1, n] сгенерируйте его двоичное представление.
2⃣ Проверка подстрок:
Проверьте, является ли каждое из двоичных представлений подстрокой строки s.
3⃣ Возврат результата:
Если все двоичные представления являются подстроками строки s, верните true. В противном случае, верните false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Если задана двоичная строка s и положительное целое число n, верните true, если двоичное представление всех целых чисел в диапазоне [1, n] является подстрокой s, или false в противном случае. Подстрока - это непрерывная последовательность символов в строке.
Пример:
Input: s = "0110", n = 3
Output: true
Для каждого числа в диапазоне [1, n] сгенерируйте его двоичное представление.
Проверьте, является ли каждое из двоичных представлений подстрокой строки s.
Если все двоичные представления являются подстроками строки s, верните true. В противном случае, верните false.
class Solution {
func queryString(_ s: String, _ n: Int) -> Bool {
for i in 1...n {
let binary = String(i, radix: 2)
if !s.contains(binary) {
return false
}
}
return true
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 476. Number Complement
Сложность: easy
Дополнение целого числа — это число, которое получается при замене всех 0 на 1 и всех 1 на 0 в его двоичном представлении.
Например, целое число 5 в двоичной системе — "101", и его дополнение — "010", что соответствует целому числу 2. Дано целое число num, верните его дополнение.
Пример:
👨💻 Алгоритм:
1⃣ Вычислите длину в битах входного числа: l=⌊log 2 (num)⌋+1.
2⃣ Постройте битовую маску из 1-битов длины l: bitmask=(1≪l)−1.
3⃣ Верните результат операции XOR числа и битовой маски: num⊕bitmask num⊕bitmask.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дополнение целого числа — это число, которое получается при замене всех 0 на 1 и всех 1 на 0 в его двоичном представлении.
Например, целое число 5 в двоичной системе — "101", и его дополнение — "010", что соответствует целому числу 2. Дано целое число num, верните его дополнение.
Пример:
Input: num = 5
Output: 2
Explanation: The binary representation of 5 is 101 (no leading zero bits), and its complement is 010. So you need to output 2.
class Solution {
func findComplement(_ num: Int) -> Int {
var bitmask = num
bitmask |= (bitmask >> 1)
bitmask |= (bitmask >> 2)
bitmask |= (bitmask >> 4)
bitmask |= (bitmask >> 8)
bitmask |= (bitmask >> 16)
return bitmask ^ num
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 733. Flood Fill
Сложность: easy
Изображение представлено в виде целочисленной сетки m x n, где image[i][j] - значение пикселя изображения. Вам также даны три целых числа sr, sc и color. Вы должны выполнить заливку изображения, начиная с пикселя image[sr][sc]. Чтобы выполнить заливку, рассмотрите начальный пиксель, плюс все пиксели, соединенные по 4-м направлениям с начальным пикселем, того же цвета, что и начальный пиксель, плюс все пиксели, соединенные по 4-м направлениям с этими пикселями (также того же цвета), и так далее. Замените цвет всех вышеупомянутых пикселей на цвет. Верните измененное изображение после выполнения заливки.
Пример:
👨💻 Алгоритм:
1⃣ Получите цвет начального пикселя.
2⃣ Используйте обход в глубину (DFS) или обход в ширину (BFS) для замены цвета всех пикселей, которые соединены с начальным пикселем и имеют тот же цвет.
3⃣ Обновите изображение и верните его.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Изображение представлено в виде целочисленной сетки m x n, где image[i][j] - значение пикселя изображения. Вам также даны три целых числа sr, sc и color. Вы должны выполнить заливку изображения, начиная с пикселя image[sr][sc]. Чтобы выполнить заливку, рассмотрите начальный пиксель, плюс все пиксели, соединенные по 4-м направлениям с начальным пикселем, того же цвета, что и начальный пиксель, плюс все пиксели, соединенные по 4-м направлениям с этими пикселями (также того же цвета), и так далее. Замените цвет всех вышеупомянутых пикселей на цвет. Верните измененное изображение после выполнения заливки.
Пример:
Input: image = [[1,1,1],[1,1,0],[1,0,1]], sr = 1, sc = 1, color = 2
Output: [[2,2,2],[2,2,0],[2,0,1]]
func floodFill(_ image: [[Int]], _ sr: Int, _ sc: Int, _ color: Int) -> [[Int]] {
var image = image
let originalColor = image[sr][sc]
if originalColor == color {
return image
}
func dfs(_ x: Int, _ y: Int) {
if x < 0 || x >= image.count || y < 0 || y >= image[0].count || image[x][y] != originalColor {
return
}
image[x][y] = color
dfs(x + 1, y)
dfs(x - 1, y)
dfs(x, y + 1)
dfs(x, y - 1)
}
dfs(sr, sc)
return image
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1496. Path Crossing
Сложность: easy
Дана строка path, где path[i] = 'N', 'S', 'E' или 'W', каждая из которых представляет движение на одну единицу на север, юг, восток или запад соответственно. Вы начинаете с точки (0, 0) на 2D плоскости и идете по пути, указанному в path.
Верните true, если путь пересекает сам себя в какой-либо точке, то есть если вы в какой-то момент окажетесь в месте, которое уже посещали ранее. В противном случае верните false.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация переменных:
Создать хэш-карту moves, которая сопоставляет символы 'N', 'S', 'E', 'W' с соответствующими значениями.
Инициализировать множество visited с начальной точкой (0, 0).
Установить начальные координаты x = 0 и y = 0.
2⃣ Проход по строке path:
Для каждого символа c в path получить значения (dx, dy) из moves[c].
Обновить координаты: добавить dx к x и dy к y.
Проверить, содержится ли текущая точка (x, y) в visited. Если да, вернуть true.
Добавить текущую точку (x, y) в visited.
3⃣ Возврат результата:
Если ни одна точка не пересекалась, вернуть false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дана строка path, где path[i] = 'N', 'S', 'E' или 'W', каждая из которых представляет движение на одну единицу на север, юг, восток или запад соответственно. Вы начинаете с точки (0, 0) на 2D плоскости и идете по пути, указанному в path.
Верните true, если путь пересекает сам себя в какой-либо точке, то есть если вы в какой-то момент окажетесь в месте, которое уже посещали ранее. В противном случае верните false.
Пример:
Input: path = "NESWW"
Output: true
Explanation: Notice that the path visits the origin twice.
Создать хэш-карту moves, которая сопоставляет символы 'N', 'S', 'E', 'W' с соответствующими значениями.
Инициализировать множество visited с начальной точкой (0, 0).
Установить начальные координаты x = 0 и y = 0.
Для каждого символа c в path получить значения (dx, dy) из moves[c].
Обновить координаты: добавить dx к x и dy к y.
Проверить, содержится ли текущая точка (x, y) в visited. Если да, вернуть true.
Добавить текущую точку (x, y) в visited.
Если ни одна точка не пересекалась, вернуть false.
class Solution {
func isPathCrossing(_ path: String) -> Bool {
let moves: [Character: (Int, Int)] = [
"N": (0, 1), "S": (0, -1),
"E": (1, 0), "W": (-1, 0)
]
var visited: Set<[Int]> = [[0, 0]]
var x = 0, y = 0
for c in path {
let move = moves[c]!
x += move.0
y += move.1
let point = [x, y]
if visited.contains(point) {
return true
}
visited.insert(point)
}
return false
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 494. Target Sum
Сложность: medium
Вам дан массив целых чисел nums и целое число target.
Вы хотите создать выражение из nums, добавляя один из символов '+' или '-' перед каждым числом в nums, а затем объединяя все числа.
Например, если nums = [2, 1], вы можете добавить '+' перед 2 и '-' перед 1, а затем объединить их, чтобы получить выражение "+2-1".
Верните количество различных выражений, которые можно построить и которые оцениваются в target.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация и вызов рекурсивной функции
Создайте переменную для хранения количества решений (count). Вызовите рекурсивную функцию calculate с начальными параметрами (nums, начальный индекс 0, начальная сумма 0, и target).
2⃣ Рекурсивная функция calculate
Если текущий индекс равен длине массива, проверьте, равна ли текущая сумма значению target. Если да, увеличьте счетчик решений. В противном случае, вызовите функцию рекурсивно дважды: добавляя и вычитая текущее значение из суммы.
3⃣ Возврат результата
После завершения всех рекурсивных вызовов верните значение счетчика решений.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан массив целых чисел nums и целое число target.
Вы хотите создать выражение из nums, добавляя один из символов '+' или '-' перед каждым числом в nums, а затем объединяя все числа.
Например, если nums = [2, 1], вы можете добавить '+' перед 2 и '-' перед 1, а затем объединить их, чтобы получить выражение "+2-1".
Верните количество различных выражений, которые можно построить и которые оцениваются в target.
Пример:
Input: nums = [1,1,1,1,1], target = 3
Output: 5
Explanation: There are 5 ways to assign symbols to make the sum of nums be target 3.
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3
Создайте переменную для хранения количества решений (count). Вызовите рекурсивную функцию calculate с начальными параметрами (nums, начальный индекс 0, начальная сумма 0, и target).
Если текущий индекс равен длине массива, проверьте, равна ли текущая сумма значению target. Если да, увеличьте счетчик решений. В противном случае, вызовите функцию рекурсивно дважды: добавляя и вычитая текущее значение из суммы.
После завершения всех рекурсивных вызовов верните значение счетчика решений.
class Solution {
var count = 0
func findTargetSumWays(_ nums: [Int], _ S: Int) -> Int {
calculate(nums, 0, 0, S)
return count
}
func calculate(_ nums: [Int], _ i: Int, _ sum: Int, _ S: Int) {
if i == nums.count {
if sum == S {
count += 1
}
} else {
calculate(nums, i + 1, sum + nums[i], S)
calculate(nums, i + 1, sum - nums[i], S)
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 380. Insert Delete GetRandom O(1)
Сложность: medium
Реализуйте класс RandomizedSet:
RandomizedSet(): Инициализирует объект RandomizedSet.
bool insert(int val): Вставляет элемент val в множество, если его там нет. Возвращает true, если элемент отсутствовал, и false в противном случае.
bool remove(int val): Удаляет элемент val из множества, если он присутствует. Возвращает true, если элемент присутствовал, и false в противном случае.
int getRandom(): Возвращает случайный элемент из текущего множества элементов (гарантируется, что по крайней мере один элемент существует при вызове этого метода). Каждый элемент должен иметь равную вероятность быть возвращенным.
Вы должны реализовать функции класса таким образом, чтобы каждая функция работала в среднем за O(1) по времени.
Пример:
👨💻 Алгоритм:
1⃣ Создать словарь для хранения значений и их индексов, а также список для хранения значений.
2⃣ Метод insert(val): Проверить наличие значения в словаре. Если отсутствует, добавить значение в список и обновить словарь с новым индексом.
Метод remove(val): Проверить наличие значения в словаре. Если присутствует, заменить удаляемое значение последним элементом списка, обновить его индекс в словаре, удалить последний элемент из списка и удалить значение из словаря.
3⃣ Метод getRandom(): Возвращать случайный элемент из списка, используя встроенную функцию генерации случайных чисел.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Реализуйте класс RandomizedSet:
RandomizedSet(): Инициализирует объект RandomizedSet.
bool insert(int val): Вставляет элемент val в множество, если его там нет. Возвращает true, если элемент отсутствовал, и false в противном случае.
bool remove(int val): Удаляет элемент val из множества, если он присутствует. Возвращает true, если элемент присутствовал, и false в противном случае.
int getRandom(): Возвращает случайный элемент из текущего множества элементов (гарантируется, что по крайней мере один элемент существует при вызове этого метода). Каждый элемент должен иметь равную вероятность быть возвращенным.
Вы должны реализовать функции класса таким образом, чтобы каждая функция работала в среднем за O(1) по времени.
Пример:
Input
["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
Output
[null, true, false, true, 2, true, false, 2]
Метод remove(val): Проверить наличие значения в словаре. Если присутствует, заменить удаляемое значение последним элементом списка, обновить его индекс в словаре, удалить последний элемент из списка и удалить значение из словаря.
class RandomizedSet {
private var dict: [Int: Int]
private var list: [Int]
init() {
dict = [Int: Int]()
list = [Int]()
}
func insert(_ val: Int) -> Bool {
if dict[val] != nil {
return false
}
dict[val] = list.count
list.append(val)
return true
}
func remove(_ val: Int) -> Bool {
guard let index = dict[val] else {
return false
}
let lastElement = list.removeLast()
if index < list.count {
list[index] = lastElement
dict[lastElement] = index
}
dict[val] = nil
return true
}
func getRandom() -> Int {
return list.randomElement()!
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 205. Isomorphic Strings
Сложность: easy
Даны две строки s и t, определите, являются ли они изоморфными.
Две строки s и t являются изоморфными, если символы в s могут быть заменены для получения t.
Все вхождения одного символа должны быть заменены другим символом, сохраняя порядок символов. Два символа не могут отображаться в один и тот же символ, но один символ может отображаться сам на себя.
Пример:
👨💻 Алгоритм:
1⃣ Определите два словаря: mapping_s_t для отображения символов из строки s в символы строки t, и mapping_t_s для отображения символов из строки t в символы строки s.
2⃣ Итеративно пройдитесь по символам строк s и t. Для каждого символа c1 из s и соответствующего c2 из t, если c1 нет в mapping_s_t и c2 нет в mapping_t_s, добавьте соответствующие отображения; если одно из отображений существует, проверьте, соответствует ли оно ожидаемому значению.
3⃣ Если в процессе проверки какое-либо отображение неверно, верните false. Если все проверки пройдены успешно, верните true после окончания итерации по строкам.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Даны две строки s и t, определите, являются ли они изоморфными.
Две строки s и t являются изоморфными, если символы в s могут быть заменены для получения t.
Все вхождения одного символа должны быть заменены другим символом, сохраняя порядок символов. Два символа не могут отображаться в один и тот же символ, но один символ может отображаться сам на себя.
Пример:
Input: s = "egg", t = "add"
Output: true
class Solution {
func isIsomorphic(_ s: String, _ t: String) -> Bool {
var mappingStoT = [Character: Character]()
var mappingTtoS = [Character: Character]()
let sArray = Array(s)
let tArray = Array(t)
for i in 0..<sArray.count {
let c1 = sArray[i]
let c2 = tArray[i]
if mappingStoT[c1] == nil && mappingTtoS[c2] == nil {
mappingStoT[c1] = c2
mappingTtoS[c2] = c1
} else if mappingStoT[c1] != c2 || mappingTtoS[c2] != c1 {
return false
}
}
return true
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 383. Ransom Note
Сложность: easy
Даны две строки ransomNote и magazine, верните true, если ransomNote можно составить, используя буквы из magazine, и false в противном случае.
Каждая буква из magazine может быть использована в ransomNote только один раз.
Пример:
👨💻 Алгоритм:
1⃣ Поскольку строки являются неизменяемым типом, их нельзя изменять, поэтому у них нет операций "вставки" и "удаления".
2⃣ По этой причине необходимо заменять строку magazine новой строкой, в которой отсутствует символ, который мы хотели удалить.
3⃣ Повторяйте этот процесс, пока не будут удалены все необходимые символы.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Даны две строки ransomNote и magazine, верните true, если ransomNote можно составить, используя буквы из magazine, и false в противном случае.
Каждая буква из magazine может быть использована в ransomNote только один раз.
Пример:
Input: ransomNote = "a", magazine = "b"
Output: false
func canConstruct(_ ransomNote: String, _ magazine: String) -> Bool {
var magazine = magazine
for char in ransomNote {
if let index = magazine.firstIndex(of: char) {
magazine.remove(at: index)
} else {
return false
}
}
return true
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1279. Traffic Light Controlled Intersection
Сложность: easy
Здесь есть пересечение двух дорог. Первая дорога - это дорога A, по которой автомобили движутся с севера на юг в направлении 1 и с юга на север в направлении 2. Вторая дорога - дорога B, по которой машины едут с запада на восток в направлении 3 и с востока на запад в направлении 4. На каждой дороге перед перекрестком есть светофор. Зеленый означает, что автомобили могут пересекать перекресток в обоих направлениях. Красный означает, что автомобили в обоих направлениях не могут пересекать перекресток и должны ждать, пока загорится зеленый свет. Светофор не может гореть зеленым одновременно на обеих дорогах. Это значит, что когда на дороге А горит зеленый свет, на дороге Б он красный, а когда на дороге Б горит зеленый свет, на дороге А он красный.
Изначально на дороге A горит зеленый сигнал светофора, а на дороге B - красный. Когда на одной дороге горит зеленый свет, все автомобили могут пересекать перекресток в обоих направлениях, пока на другой дороге не загорится зеленый.Два автомобиля, движущиеся по разным дорогам, не должны пересекать перекресток одновременно. Разработайте систему управления светофором на этом перекрестке без тупиков. Реализуйте функцию void carArrived(carId, roadId, direction, turnGreen, crossCar), где: carId - идентификатор автомобиля, который приехал. roadId - идентификатор дороги, по которой едет автомобиль.
direction - направление движения автомобиля. turnGreen - функция, которую можно вызвать, чтобы переключить светофор на зеленый свет на текущей дороге. crossCar - функция, которую можно вызвать, чтобы позволить текущему автомобилю пересечь перекресток. Ваш ответ считается правильным, если он позволяет избежать тупика на перекрестке.Переключение светофора на зеленый свет на дороге, где он уже был зеленым, считается неправильным ответом.
Пример:
👨💻 Алгоритм:
1⃣ Если на дороге, по которой едет автомобиль, уже зеленый свет, вызываем функцию crossCar.
2⃣ Если на дороге, по которой едет автомобиль, красный свет, вызываем функцию turnGreen, чтобы переключить свет на зеленый, и затем вызываем функцию crossCar.
3⃣ Обеспечиваем, что функции turnGreen и crossCar вызываются атомарно для предотвращения гонок и тупиков.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Здесь есть пересечение двух дорог. Первая дорога - это дорога A, по которой автомобили движутся с севера на юг в направлении 1 и с юга на север в направлении 2. Вторая дорога - дорога B, по которой машины едут с запада на восток в направлении 3 и с востока на запад в направлении 4. На каждой дороге перед перекрестком есть светофор. Зеленый означает, что автомобили могут пересекать перекресток в обоих направлениях. Красный означает, что автомобили в обоих направлениях не могут пересекать перекресток и должны ждать, пока загорится зеленый свет. Светофор не может гореть зеленым одновременно на обеих дорогах. Это значит, что когда на дороге А горит зеленый свет, на дороге Б он красный, а когда на дороге Б горит зеленый свет, на дороге А он красный.
Изначально на дороге A горит зеленый сигнал светофора, а на дороге B - красный. Когда на одной дороге горит зеленый свет, все автомобили могут пересекать перекресток в обоих направлениях, пока на другой дороге не загорится зеленый.Два автомобиля, движущиеся по разным дорогам, не должны пересекать перекресток одновременно. Разработайте систему управления светофором на этом перекрестке без тупиков. Реализуйте функцию void carArrived(carId, roadId, direction, turnGreen, crossCar), где: carId - идентификатор автомобиля, который приехал. roadId - идентификатор дороги, по которой едет автомобиль.
direction - направление движения автомобиля. turnGreen - функция, которую можно вызвать, чтобы переключить светофор на зеленый свет на текущей дороге. crossCar - функция, которую можно вызвать, чтобы позволить текущему автомобилю пересечь перекресток. Ваш ответ считается правильным, если он позволяет избежать тупика на перекрестке.Переключение светофора на зеленый свет на дороге, где он уже был зеленым, считается неправильным ответом.
Пример:
Input: cars = [1,2,3,4,5], directions = [2,4,3,3,1], arrivalTimes = [10,20,30,40,40]
Output: [
"Car 1 Has Passed Road A In Direction 2", // Traffic light on road A is green, car 1 can cross the intersection.
"Traffic Light On Road B Is Green", // Car 2 requests green light for road B.
"Car 2 Has Passed Road B In Direction 4", // Car 2 crosses as the light is green on road B now.
"Car 3 Has Passed Road B In Direction 3", // Car 3 crosses as the light is green on road B now.
"Traffic Light On Road A Is Green", // Car 5 requests green light for road A.
"Car 5 Has Passed Road A In Direction 1", // Car 5 crosses as the light is green on road A now.
"Traffic Light On Road B Is Green", // Car 4 requests green light for road B. Car 4 blocked until car 5 crosses and then traffic light is green on road B.
"Car 4 Has Passed Road B In Direction 3" // Car 4 crosses as the light is green on road B now.
]
import Foundation
class TrafficLight {
private var greenRoad = 1
private let lock = NSLock()
func carArrived(
_ carId: Int,
_ roadId: Int,
_ direction: Int,
_ turnGreen: () -> Void,
_ crossCar: () -> Void
) {
lock.lock()
defer { lock.unlock() }
if greenRoad != roadId {
turnGreen()
greenRoad = roadId
}
crossCar()
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM