TGViewer
Channel Public Channel
Swift | LeetCode

Swift | LeetCode

@easy_swift_task

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

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

Showing posts older than #1522 · Back to latest

Older Posts 20 shown
Post #1520 85
Задача: 1359. Count All Valid Pickup and Delivery Options
Сложность: hard

Дано n заказов, каждый из которых состоит из услуги забора и доставки.

Посчитайте все возможные допустимые последовательности забора/доставки, такие что доставка(i) всегда идет после забора(i).

Поскольку ответ может быть слишком большим, верните его по модулю 10^9 + 7.

Пример:
Input: n = 1
Output: 1
Explanation: Unique order (P1, D1), Delivery 1 always is after of Pickup 1.


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

1⃣Инициализация:
Используйте динамическое программирование для хранения количества допустимых последовательностей для каждого количества заказов от 1 до n.

2⃣Рекурсивное вычисление:
Для каждого количества заказов k используйте рекурсивную формулу для вычисления количества допустимых последовательностей, учитывая, что каждая новая пара (забор и доставка) может быть вставлена в любую из существующих позиций.

3⃣Возвращение результата:
Верните результат для n заказов, применяя модуль 10^9 + 7 для предотвращения переполнения.

😎 Решение:
class Solution {
func countOrders(_ n: Int) -> Int {
let MOD = 1_000_000_007
var dp = [Int](repeating: 0, count: n + 1)
dp[0] = 1

for i in 1...n {
dp[i] = dp[i - 1] * (2 * i - 1) * i % MOD
}

return dp[n]
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1519 98
Задача: 96. Unique Binary Search Trees
Сложность: medium

Дано целое число n. Верните количество структурно уникальных деревьев бинарного поиска (BST), которые содержат ровно n узлов с уникальными значениями от 1 до n.

Пример:
Input: n = 3
Output: 5


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

1⃣Задача состоит в том, чтобы рассчитать количество уникальных BST (бинарных деревьев поиска). Для этого мы можем определить две функции:

G(n): количество уникальных BST для последовательности длины n.

F(i, n): количество уникальных BST, где число i является корнем BST (1 ≤ i ≤ n).

Как видно, G(n) - это именно та функция, которая нам нужна для решения задачи.

2⃣Позднее мы увидим, что G(n) можно вывести из F(i, n), которая, в свою очередь, рекурсивно относится к G(n).

Следуя идее из раздела "Интуиция", мы видим, что общее количество уникальных BST G(n) равно сумме BST F(i, n) с перечислением каждого числа i (1 ≤ i ≤ n) в качестве корня. Таким образом,

G(n) = ∑ F(i, n) для i от 1 до n.

В частности, для базовых случаев есть только одна комбинация для построения BST из последовательности длиной 1 (только корень) или ничего (пустое дерево). То есть G(0) = 1, G(1) = 1.

3⃣Дана последовательность от 1 до n, мы выбираем число i из последовательности в качестве корня, тогда количество уникальных BST с указанным корнем, определенным как F(i, n), является декартовым произведением количества BST для его левого и правого поддеревьев, как показано ниже:

Например, F(3,7) - количество уникальных деревьев BST с числом 3 в качестве корня. Для построения уникального BST из всей последовательности [1, 2, 3, 4, 5, 6, 7] с 3 в качестве корня, мы должны построить поддерево из его левой подпоследовательности [1, 2] и другое поддерево из правой подпоследовательности [4, 5, 6, 7], а затем соединить их вместе (то есть декартово произведение). Теперь хитрость заключается в том, что мы можем рассматривать количество уникальных BST из последовательности [1,2] как G(2), и количество уникальных BST из последовательности [4, 5, 6, 7] как G(4). Для G(n) не имеет значения содержание последовательности, а только длина последовательности. Следовательно, F(3,7) = G(2)⋅G(4). Обобщая пример, мы можем вывести следующую формулу:

F(i, n) = G(i−1)⋅G(n−i)

Объединяя формулы (1), (2), мы получаем рекурсивную формулу для G(n), то есть

G(n) = ∑ G(i−1)⋅G(n−i) для i от 1 до n.

Чтобы вычислить результат функции, мы начинаем с меньшего числа, так как значение G(n) зависит от значений G(0)...G(n−1).

😎 Решение:
class Solution {
func numTrees(_ n: Int) -> Int {
var G = Array(repeating: 0, count: n + 1)
G[0] = 1
G[1] = 1

for i in 2...n {
for j in 1...i {
G[i] += G[j - 1] * G[i - j]
}
}

return G[n]
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1518 103
Задача: 1038. Binary Search Tree to Greater Sum Tree
Сложность: medium

Получив корень двоичного дерева поиска (BST), преобразуйте его в большее дерево таким образом, чтобы каждый ключ исходного BST был заменен на исходный ключ плюс сумма всех ключей, превышающих исходный ключ в BST. Напомним, что двоичное дерево поиска - это дерево, удовлетворяющее следующим ограничениям: левое поддерево узла содержит только узлы с ключами меньше, чем ключ узла. Правое поддерево узла содержит только узлы с ключами больше, чем ключ узла. И левое, и правое поддеревья должны быть двоичными деревьями поиска.

Пример:
Input: root = [4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
Output: [30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]


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

1⃣Обратный обход in-order:
Пройдите по дереву в порядке "правый, корень, левый" (обратный in-order обход). Это обеспечит посещение узлов в порядке убывания их значений.

2⃣Накопление суммы:
Во время обхода поддерживайте переменную для хранения накопленной суммы. На каждом узле добавляйте значение узла к накопленной сумме и обновляйте значение узла этой накопленной суммой.

3⃣Преобразование узлов:
Преобразуйте значение каждого узла в накопленную сумму.

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

class Solution {
var sum = 0

func bstToGst(_ root: TreeNode?) -> TreeNode? {
reverseInorder(root)
return root
}

func reverseInorder(_ node: TreeNode?) {
guard let node = node else { return }
reverseInorder(node.right)
sum += node.val
node.val = sum
reverseInorder(node.left)
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1516 89
Задача: 1365. How Many Numbers Are Smaller Than the Current Number
Сложность: easy

Дан массив nums. Для каждого элемента nums[i] определите, сколько чисел в массиве меньше его. То есть, для каждого nums[i] вам нужно посчитать количество допустимых j, таких что j != i и nums[j] < nums[i].

Верните ответ в виде массива.

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


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

1⃣Создание копии и сортировка массива:
Создайте отсортированную копию массива nums, чтобы легко находить количество элементов, меньших текущего.

2⃣Поиск индекса каждого элемента:
Для каждого элемента nums[i] найдите его индекс в отсортированной копии массива. Этот индекс указывает количество элементов, меньших nums[i].

3⃣Формирование ответа:
Сформируйте массив ответов, где каждый элемент будет соответствовать количеству чисел, меньших текущего.

😎 Решение:
class Solution {
func smallerNumbersThanCurrent(_ nums: [Int]) -> [Int] {
let sortedNums = nums.sorted()
var result = [Int]()

for num in nums {
result.append(sortedNums.firstIndex(of: num)!)
}

return result
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1515 108
Задача: 190. Reverse Bits
Сложность: easy

Переверните биты заданного 32-битного беззнакового целого числа.

Пример:
Input: n = 00000010100101000001111010011100
Output: 964176192 (00111001011110000010100101000000)
Explanation: The input binary string 00000010100101000001111010011100 represents the unsigned integer 43261596, so return 964176192 which its binary representation is 00111001011110000010100101000000.
Example 2:


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

1⃣Итерируем по байтам целого числа, используя побитовую операцию И (n & 0xff) с маской 11111111, чтобы извлечь крайний правый байт числа.

2⃣Для каждого байта сначала переворачиваем биты внутри байта с помощью функции reverseByte(byte). Затем сдвигаем перевернутые биты на их окончательные позиции.

3⃣В функции reverseByte(byte) используем технику мемоизации, которая сохраняет результат функции и возвращает его непосредственно при последующих вызовах с тем же входным значением. Мемоизация — это компромисс между использованием памяти и объемом вычислений.

😎 Решение:
class Solution {
var cache = [UInt32: UInt32]()

func reverseByte(_ byte: UInt32) -> UInt32 {
if let cachedValue = cache[byte] {
return cachedValue
}
let value = ((byte * 0x0202020202) & 0x010884422010) % 1023
cache[byte] = value
return value
}

func reverseBits(_ n: UInt32) -> UInt32 {
var ret: UInt32 = 0
var power: UInt32 = 24
var n = n
while n != 0 {
ret += reverseByte(n & 0xff) << power
n = n >> 8
power -= 8
}
return ret
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1514 108
Задача: 141. Linked List Cycle
Сложность: easy

Дана переменная head, которая является началом связного списка. Определите, содержит ли связный список цикл.

Цикл в связном списке существует, если существует узел в списке, до которого можно добраться снова, последовательно следуя по указателю next. Внутренне переменная pos используется для обозначения индекса узла, к которому подключен указатель next последнего узла. Обратите внимание, что pos не передается в качестве параметра.

Верните true, если в связном списке есть цикл. В противном случае верните false.

Пример:
Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where the tail connects to the 1st node (0-indexed).


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

1⃣Инициализация структуры данных:
Создайте хеш-таблицу (или множество) для хранения ссылок на узлы, чтобы отслеживать уже посещённые узлы.

2⃣Обход списка:
Перемещайтесь по связному списку, начиная с головы (head), и проверяйте каждый узел по очереди.

3⃣Проверка на цикл:
Если текущий узел равен null, это означает, что вы достигли конца списка, и список не имеет циклов. В этом случае верните false.
Если текущий узел уже содержится в хеш-таблице, это означает, что вы вернулись к ранее посещённому узлу, и, следовательно, в списке присутствует цикл. Верните true.
Если ни одно из этих условий не выполнено, добавьте текущий узел в хеш-таблицу и продолжите обход списка.

😎 Решение:
class ListNode {
var val: Int
var next: ListNode?

init(_ val: Int, _ next: ListNode? = nil) {
self.val = val
self.next = next
}
}

class Solution {
func hasCycle(_ head: ListNode?) -> Bool {
var nodesSeen = Set<ListNode>()
var current = head

while current != nil {
if nodesSeen.contains(current!) {
return true
}
nodesSeen.insert(current!)
current = current?.next
}
return false
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1513 99
Задача: 275. H-Index II
Сложность: medium

Дан массив целых чисел citations, где citations[i] — количество цитирований, которое исследователь получил за свою i-ю статью, и массив отсортирован в порядке возрастания. Верните h-индекс исследователя.
Согласно определению h-индекса на Википедии: h-индекс определяется как максимальное значение h, такое что данный исследователь опубликовал по крайней мере h статей, каждая из которых была процитирована как минимум h раз.
Вы должны написать алгоритм, который работает за логарифмическое время.

Пример:
Input: citations = [0,1,3,5,6]
Output: 3
Explanation: [0,1,3,5,6] means the researcher has 5 papers in total and each of them had received 0, 1, 3, 5, 6 citations respectively.
Since the researcher has 3 papers with at least 3 citations each and the remaining two with no more than 3 citations each, their h-index is 3.


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

1⃣Найти середину массива:
Определить средний элемент массива, чтобы разделить его на две подмножества: citations[0: mid - 1] и citations[mid + 1: n].

2⃣Сравнить количество статей с цитированиями больше или равными citations[mid]:
Если citations[mid] == n - mid, то найден h-индекс и его можно вернуть.
Если citations[mid] < n - mid, то необходимо искать в правой подмножности citations[mid + 1: n].
Если citations[mid] > n - mid, то необходимо искать в левой подмножности citations[0: mid - 1].

3⃣Возвращение результата:
Продолжать процесс, пока не будет найден h-индекс.
Возвратить n - mid, что является количеством статей с цитированиями больше или равными citations[mid].

😎 Решение:
class Solution {
func hIndex(_ citations: [Int]) -> Int {
let n = citations.count
var left = 0
var right = n - 1

while left <= right {
let mid = left + (right - left) / 2
if citations[mid] == n - mid {
return n - mid
} else if citations[mid] < n - mid {
left = mid + 1
} else {
right = mid - 1
}
}
return n - left
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1512 88
Задача: 91. Decode Ways
Сложность: medium

Сообщение, содержащее буквы от A до Z, можно закодировать в числа с использованием следующего соответствия:

- 'A' -> "1"
- 'B' -> "2"
- ...
- 'Z' -> "26"

Для декодирования закодированного сообщения все цифры должны быть сгруппированы и затем отображены обратно в буквы с использованием обратного соответствия (существует несколько способов). Например, "11106" можно представить как:

- "AAJF" с группировкой (1 1 10 6)
- "KJF" с группировкой (11 10 6)

Обратите внимание, что группировка (1 11 06) недопустима, потому что "06" не может быть преобразовано в 'F', так как "6" отличается от "06".

Для данной строки s, содержащей только цифры, верните количество способов декодирования.

Тестовые случаи сформированы таким образом, что ответ укладывается в 32-битное целое число.

Пример:
Input: s = "12"
Output: 2
Explanation: "12" could be decoded as "AB" (1 2) or "L" (12).


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


1⃣Входим в рекурсию с данной строкой, начиная с индекса 0.

2⃣Для окончательного случая рекурсии мы проверяем конец строки. Если мы достигли конца строки, возвращаем 1. Каждый раз, когда мы входим в рекурсию, это для подстроки исходной строки. Если первый символ в подстроке равен 0, то прекращаем этот путь, возвращая 0. Таким образом, этот путь не будет влиять на количество способов.

3⃣Мемоизация помогает снизить сложность, которая иначе была бы экспоненциальной. Мы проверяем словарь memo, чтобы увидеть, существует ли уже результат для данной подстроки. Если результат уже находится в memo, мы возвращаем этот результат. В противном случае количество способов для данной строки определяется путем рекурсивного вызова функции с индексом +1 для следующей подстроки и индексом +2 после проверки на валидность двузначного декодирования. Результат также сохраняется в memo с ключом как текущий индекс, чтобы сохранить его для будущих пересекающихся подзадач.


😎 Решение:
import Foundation

class Solution {
private var memo: [Int: Int] = [:]

private func recursiveWithMemo(_ index: Int, _ s: String) -> Int {
if index == s.count {
return 1
}

let startIndex = s.index(s.startIndex, offsetBy: index)
let firstChar = s[startIndex]

if firstChar == "0" {
return 0
}

if index == s.count - 1 {
return 1
}

if let cachedResult = memo[index] {
return cachedResult
}

let nextIndex = s.index(after: startIndex)
var answer = recursiveWithMemo(index + 1, s)

if index < s.count - 1 {
let secondIndex = s.index(after: nextIndex)
let range = startIndex..<secondIndex
let number = Int(s[range])!

if number <= 26 {
answer += recursiveWithMemo(index + 2, s)
}
}

memo[index] = answer
return answer
}

func numDecodings(_ s: String) -> Int {
return recursiveWithMemo(0, s)
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1511 94
Задача: 1129. Shortest Path with Alternating Colors
Сложность: medium

Вам дано целое число n, количество узлов в ориентированном графе, где узлы помечены от 0 до n - 1. Каждое ребро в этом графе может быть красным или синим, и могут быть самопетли и параллельные ребра.

Вам даны два массива redEdges и blueEdges, где:
redEdges[i] = [ai, bi] указывает, что в графе существует направленное красное ребро от узла ai к узлу bi, и
blueEdges[j] = [uj, vj] указывает, что в графе существует направленное синее ребро от узла uj к узлу vj.
Верните массив answer длины n, где каждый answer[x] — это длина кратчайшего пути от узла 0 до узла x, такого что цвета ребер чередуются вдоль пути, или -1, если такого пути не существует.

Пример:
Input: n = 3, redEdges = [[0,1],[1,2]], blueEdges = []
Output: [0,1,-1]


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

1⃣Создание структуры данных и инициализация:
Создайте список смежности adj, который будет содержать пары (сосед, цвет) для каждого узла.
Создайте массив answer длиной n, инициализированный значением -1, чтобы хранить длину кратчайшего пути для каждого узла.
Создайте 2D массив visit для отслеживания, были ли узлы посещены с использованием ребра определённого цвета.

2⃣Инициализация очереди и начальных условий:
Создайте очередь для хранения трёх значений (узел, количество шагов, цвет предыдущего ребра).
Добавьте в очередь начальный узел (0, 0, -1) и установите visit[0][0] и visit[0][1] в true, так как повторное посещение узла 0 бессмысленно.

3⃣Обработка очереди и обновление результата:
Пока очередь не пуста, извлекайте элемент из очереди и получайте (узел, количество шагов, цвет предыдущего ребра).
Для каждого соседа, если сосед не был посещён с использованием ребра текущего цвета и текущий цвет не равен предыдущему, обновите массив answer и добавьте соседа в очередь.

😎 Решение:
class Solution {
func shortestAlternatingPaths(_ n: Int, _ redEdges: [[Int]], _ blueEdges: [[Int]]) -> [Int] {
var adj = [Int: [[Int]]]()
for redEdge in redEdges {
adj[redEdge[0], default: []].append([redEdge[1], 0])
}
for blueEdge in blueEdges {
adj[blueEdge[0], default: []].append([blueEdge[1], 1])
}

var answer = [Int](repeating: -1, count: n)
var visit = Array(repeating: [false, false], count: n)
var queue = [(0, 0, -1)]
answer[0] = 0
visit[0][0] = true
visit[0][1] = true

while !queue.isEmpty {
let (node, steps, prevColor) = queue.removeFirst()

if let neighbors = adj[node] {
for neighbor in neighbors {
let nextNode = neighbor[0]
let color = neighbor[1]
if !visit[nextNode][color] && color != prevColor {
if answer[nextNode] == -1 {
answer[nextNode] = steps + 1
}
visit[nextNode][color] = true
queue.append((nextNode, steps + 1, color))
}
}
}
}
return answer
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1510 98
Задача: 1200. Minimum Absolute Difference
Сложность: easy

Дан массив различных целых чисел arr, найдите все пары элементов с минимальной абсолютной разницей между любыми двумя элементами.

Верните список пар в порядке возрастания (по отношению к парам), каждая пара [a, b] следует условиям:
a, b из arr
a < b
b - a равна минимальной абсолютной разнице между любыми двумя элементами в arr

Пример:
Input: arr = [4,2,1,3]
Output: [[1,2],[2,3],[3,4]]
Explanation: The minimum absolute difference is 1. List all pairs with difference equal to 1 in ascending order.


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

1⃣Инициализация вспомогательного массива:
Найдите минимальный элемент minElement и максимальный элемент maxElement в массиве arr.
Инициализируйте вспомогательный массив line размером maxElement - minElement + 1 и установите смещение shift равным -minElement.
Пройдите по массиву arr и для каждого элемента value увеличьте значение в индексе value + shift на 1.

2⃣Поиск минимальной абсолютной разницы:
Пройдите по вспомогательному массиву line, начиная с индекса, соответствующего минимальному элементу.
Проверьте значения на каждом индексе curr:
- если line[curr] равно 0, пропустите этот индекс.
- если line[curr] равно 1, сравните абсолютную разницу текущей пары currPairDiff с минимальной найденной разницей minPairDiff.
- если currPairDiff больше minPairDiff, продолжайте.
- если currPairDiff равно minPairDiff, добавьте эту пару в список ответов.
- если currPairDiff меньше minPairDiff, очистите список ответов, добавьте эту пару и обновите minPairDiff.

3⃣Возврат результата:
После прохождения всех элементов массива line, список ответов будет содержать все пары с минимальной абсолютной разницей. Верните список ответов.

😎 Решение:
class Solution {
func minimumAbsDifference(_ arr: [Int]) -> [[Int]] {
let sortedArr = arr.sorted()
var minDiff = Int.max
var result = [[Int]]()

for i in 1..<sortedArr.count {
let diff = sortedArr[i] - sortedArr[i - 1]
if diff < minDiff {
minDiff = diff
result = [[sortedArr[i - 1], sortedArr[i]]]
} else if diff == minDiff {
result.append([sortedArr[i - 1], sortedArr[i]])
}
}

return result
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1509 109
Задача: 239. Sliding Window Maximum
Сложность: hard

Вам дан массив целых чисел nums. Существует скользящее окно размера k, которое перемещается с самого левого конца массива до самого правого. Вы можете видеть только k чисел в окне. Каждый раз скользящее окно перемещается вправо на одну позицию.

Верните максимальные значения скользящего окна.

Пример:
Input: nums = [1], k = 1
Output: [1]


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

1⃣Инициализация и заполнение первой части окна:
Создайте двустороннюю очередь dq для хранения индексов элементов и список res для хранения результатов.
Пройдите по первым k элементам массива nums (от i = 0 до k - 1). Для каждого элемента:
Удалите из dq все элементы, которые меньше или равны текущему элементу nums[i].
Добавьте текущий индекс i в конец dq.
Добавьте в res максимальный элемент первого окна, который находится в nums[dq[0]].

2⃣Сканирование оставшейся части массива:
Пройдите по оставшимся элементам массива nums (от i = k до n - 1). Для каждого элемента:
Если индекс элемента на передней части dq равен i - k, удалите этот элемент из dq, так как он выходит за пределы текущего окна.
Удалите из dq все элементы, которые меньше или равны текущему элементу nums[i].
Добавьте текущий индекс i в конец dq.
Добавьте в res максимальный элемент текущего окна, который находится в nums[dq[0]].

3⃣Возвращение результата:
Верните список res, содержащий максимальные элементы для каждого скользящего окна.

😎 Решение:
class Solution {
func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] {
var dq = [Int]()
var res = [Int]()

for i in 0..<k {
while !dq.isEmpty && nums[i] >= nums[dq.last!] {
dq.removeLast()
}
dq.append(i)
}
res.append(nums[dq.first!])

for i in k..<nums.count {
if dq.first == i - k {
dq.removeFirst()
}
while !dq.isEmpty && nums[i] >= nums[dq.last!] {
dq.removeLast()
}
dq.append(i)
res.append(nums[dq.first!])
}

return res
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1508 137
Задача: 965. Univalued Binary Tree
Сложность: easy

Бинарное дерево является одноценным, если каждый узел в дереве имеет одинаковое значение.

Дан корень бинарного дерева, верните true, если данное дерево является одноценным, или false в противном случае.

Пример:
Input: root = [1,1,1,1,1,null,1]
Output: true


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

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

2⃣Проверьте, что все значения в списке одинаковы.

3⃣Если все значения одинаковы, верните true, иначе верните false.

😎 Решение:
class Solution {
var vals: [Int] = []

func isUnivalTree(_ root: TreeNode?) -> Bool {
dfs(root)
for v in vals {
if v != vals[0] {
return false
}
}
return true
}

func dfs(_ node: TreeNode?) {
if let node = node {
vals.append(node.val)
dfs(node.left)
dfs(node.right)
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1507 160
Задача: 1318. Minimum Flips to Make a OR b Equal to c
Сложность: medium

Даны три положительных числа a, b и c. Верните минимальное количество переворотов, необходимых в некоторых битах a и b, чтобы сделать (a OR b == c) (побитовая операция OR). Операция переворота состоит из изменения любого отдельного бита с 1 на 0 или с 0 на 1 в их двоичном представлении.

Пример:
Input: a = 2, b = 6, c = 5
Output: 3
Explanation: After flips a = 1 , b = 4 , c = 5 such that (a OR b == c)


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

1⃣Инициализируйте переменную answer как 0, которая будет использоваться для отслеживания минимального количества необходимых переворотов.

2⃣Итеративно обрабатывайте каждый бит двоичного представления чисел a, b и c одновременно:
Если (c & 1) == 0, обновите answer как answer += (a & 1) + (b & 1).
Если (c & 1) == 1, и если оба значения a & 1 и b & 1 равны 0, увеличьте answer на 1.

3⃣Сдвигайте все числа вправо с помощью a >>= 1, b >>= 1, c >>= 1. Если все числа равны 0, верните answer, в противном случае, повторите шаги 2 и 3.

😎 Решение
class Solution {
func minFlips(_ a: Int, _ b: Int, _ c: Int) -> Int {
var a = a, b = b, c = c
var answer = 0
while a != 0 || b != 0 || c != 0 {
if (c & 1) == 1 {
if (a & 1) == 0 && (b & 1) == 0 {
answer += 1
}
} else {
answer += (a & 1) + (b & 1)
}
a >>= 1
b >>= 1
c >>= 1
}
return answer
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1506 131
Задача: 252. Meeting Rooms
Сложность: easy

Дан массив интервалов времени встреч, где intervals[i] = [starti, endi]. Определите, может ли человек посетить все встречи.

Пример:
Input: intervals = [[0,30],[5,10],[15,20]]
Output: false


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

1⃣Создайте функцию для проверки перекрытия двух интервалов:
Возвращайте true, если начало одного интервала находится внутри другого интервала.

2⃣Проверьте каждый интервал с каждым другим интервалом:
Если найдено перекрытие, верните false.

3⃣Если все интервалы проверены и перекрытий не найдено, верните true.

😎 Решение:
class Solution {
func overlap(_ interval1: [Int], _ interval2: [Int]) -> Bool {
return (interval1[0] >= interval2[0] && interval1[0] < interval2[1]) ||
(interval2[0] >= interval1[0] && interval2[0] < interval1[1])
}

func canAttendMeetings(_ intervals: [[Int]]) -> Bool {
for i in 0..<intervals.count {
for j in i + 1..<intervals.count {
if overlap(intervals[i], intervals[j]) {
return false
}
}
}
return true
}
}


Ставь 👍 и забирай 📚 Базу знаний
  • 👍 1
Post #1505 126
Задача: 719. Find K-th Smallest Pair Distance
Сложность: hard

Расстояние между парой целых чисел a и b определяется как абсолютная разность между a и b. Учитывая целочисленный массив nums и целое число k, верните k-е наименьшее расстояние среди всех пар nums[i] и nums[j], где 0 <= i < j < nums.length.

Пример:
Input: nums = [1,3,1], k = 1
Output: 0


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

1⃣Отсортируйте массив nums.

2⃣Определите минимальное и максимальное возможные расстояния.

3⃣Используйте бинарный поиск, чтобы найти k-е наименьшее расстояние, проверяя количество пар с расстоянием меньше или равно текущему среднему значению.

😎 Решение:
func smallestDistancePair(_ nums: [Int], _ k: Int) -> Int {
let nums = nums.sorted()

func countPairs(_ mid: Int) -> Int {
var count = 0, j = 0
for i in 0..<nums.count {
while j < nums.count && nums[j] - nums[i] <= mid {
j += 1
}
count += j - i - 1
}
return count
}

var left = 0, right = nums.last! - nums.first!
while left < right {
let mid = (left + right) / 2
if countPairs(mid) < k {
left = mid + 1
} else {
right = mid
}
}
return left
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1504 143
Задача: 1182. Shortest Distance to Target Color
Сложность: medium

Дан массив colors, содержащий три цвета: 1, 2 и 3.

Также даны несколько запросов. Каждый запрос состоит из двух целых чисел i и c. Верните наименьшее расстояние между заданным индексом i и целевым цветом c. Если решения нет, верните -1.

Пример:
Input: colors = [1,1,2,1,3,2,2,3,3], queries = [[1,3],[2,2],[6,1]]
Output: [3,0,3]
Explanation:
The nearest 3 from index 1 is at index 4 (3 steps away).
The nearest 2 from index 2 is at index 2 itself (0 steps away).
The nearest 1 from index 6 is at index 3 (3 steps away).


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

1⃣Инициализируйте хэш-таблицу для отображения каждого цвета в список индексов. Итерируйте по массиву colors и добавляйте каждый индекс в соответствующий список хэш-таблицы.

2⃣Для каждого запроса, содержащего i и c, если c не является одним из ключей в хэш-таблице, то colors не содержит c, поэтому верните -1. Иначе, найдите позицию i в соответствующем списке индексов indexList для поддержания упорядоченного порядка.

3⃣Если i меньше всех элементов в indexList, то i - indexList[0] является кратчайшим расстоянием. Если i больше всех элементов в indexList, то indexList[indexList.size() - 1] - i является кратчайшим расстоянием. Иначе, ближайшее появление c к i либо на индексе вставки, либо перед ним, поэтому рассчитайте расстояние от i до каждого из них и верните наименьшее.

😎 Решение
class Solution {
func shortestDistanceColor(_ colors: [Int], _ queries: [[Int]]) -> [Int] {
var queryResults = [Int]()
var hashmap = [Int: [Int]]()

for i in 0..<colors.count {
hashmap[colors[i], default: [Int]()].append(i)
}

for query in queries {
let target = query[0]
let color = query[1]
guard let indexList = hashmap[color] else {
queryResults.append(-1)
continue
}

let insert = indexList.binarySearch(target)

if insert < 0 {
let insertPos = -(insert + 1)
if insertPos == 0 {
queryResults.append(indexList[insertPos] - target)
} else if insertPos == indexList.count {
queryResults.append(target - indexList[insertPos - 1])
} else {
let leftNearest = target - indexList[insertPos - 1]
let rightNearest = indexList[insertPos] - target
queryResults.append(min(leftNearest, rightNearest))
}
} else {
queryResults.append(0)
}
}

return queryResults
}
}

extension Array where Element: Comparable {
func binarySearch(_ value: Element) -> Int {
var left = 0
var right = self.count - 1

while left <= right {
let mid = (left + right) / 2
if self[mid] == value {
return mid
} else if self[mid] < value {
left = mid + 1
} else {
right = mid - 1
}
}
return -(left + 1)
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1502 225
Задача: 968. Binary Tree Cameras
Сложность: hard

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

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

Пример:
Input: root = [0,0,null,0,null,0,null,null,0]
Output: 2
Explanation: At least two cameras are needed to monitor all nodes of the tree. The above image shows one of the valid configurations of camera placement.


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

1⃣Рекурсивное решение (solve):
Для каждого узла определите три состояния:
- [State 0] Строгое поддерево: все узлы ниже этого узла покрыты, но не сам узел.
- [State 1] Нормальное поддерево: все узлы ниже и включая этот узел покрыты, но на этом узле нет камеры.
- [State 2] Установленная камера: все узлы ниже и включая этот узел покрыты, и на этом узле установлена камера.
Рассчитайте эти состояния для левого и правого поддеревьев.

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

3⃣Минимальное количество камер:
Запустите функцию solve на корневом узле и верните минимальное значение между состояниями 1 и 2.

😎 Решение:
class Solution {
func minCameraCover(_ root: TreeNode?) -> Int {
let ans = solve(root)
return min(ans[1], ans[2])
}

func solve(_ node: TreeNode?) -> [Int] {
if node == nil {
return [0, 0, 99999]
}

let L = solve(node?.left)
let R = solve(node?.right)
let mL12 = min(L[1], L[2])
let mR12 = min(R[1], R[2])

let d0 = L[1] + R[1]
let d1 = min(L[2] + mR12, R[2] + mL12)
let d2 = 1 + min(L[0], mL12) + min(R[0], mR12)
return [d0, d1, d2]
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1501 151
Задача: 1134. Armstrong Number
Сложность: easy

Дано целое число n, верните true, если и только если оно является числом Армстронга.

k-значное число n является числом Армстронга, если сумма k-й степени каждой его цифры равна n.

Пример:
Input: n = 153
Output: true
Explanation: 153 is a 3-digit number, and 153 = 1^3 + 5^3 + 3^3.


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

1⃣Получите количество цифр в n, преобразовав его в строку и найдя длину.

2⃣Создайте функцию getSumOfKthPowerOfDigits(n, k), которая возвращает сумму k-й степени каждой цифры числа n.
Инициализируйте переменную result для хранения результата.
Пока n не равно 0, добавляйте k-ю степень последней цифры n к result и удаляйте последнюю цифру.

3⃣Верните true, если результат равен исходному числу n.

😎 Решение:
class Solution {
func getSumOfKthPowerOfDigits(_ n: Int, _ k: Int) -> Int {
var result = 0
var number = n
while number != 0 {
let digit = number % 10
result += Int(pow(Double(digit), Double(k)))
number /= 10
}
return result
}

func isArmstrong(_ n: Int) -> Bool {
let length = String(n).count
return getSumOfKthPowerOfDigits(n, length) == n
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1500 114
Задача: 1056. Confusing Number
Сложность: easy

Запутанное число - это число, которое при повороте на 180 градусов становится другим числом, каждая цифра которого действительна. Мы можем повернуть цифры числа на 180 градусов, чтобы получить новые цифры. Когда 0, 1, 6, 8 и 9 поворачиваются на 180 градусов, они становятся 0, 1, 9, 8 и 6 соответственно.
При повороте на 180 градусов 2, 3, 4, 5 и 7 становятся недействительными. Обратите внимание, что после поворота числа мы можем игнорировать ведущие нули. Например, после поворота 8000 мы получим 0008, которое считается просто 8. Если задано целое число n, верните true, если это запутанное число, или false в противном случае.

Пример:
Input: n = 6
Output: true


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

1⃣Преобразуй число в строку для удобства работы с его цифрами.
Используй словарь для хранения соответствий цифр при повороте на 180 градусов.

2⃣Пройди по цифрам числа, проверяя, что все цифры действительны и заменяя их на соответствующие при повороте.

3⃣Проверь, что перевернутая строка отличается от исходной.

😎 Решение:
func isConfusingNumber(_ n: Int) -> Bool {
let rotationMap: [Character: Character] = ["0": "0", "1": "1", "6": "9", "8": "8", "9": "6"]
let nStr = String(n)
var rotatedStr = ""

for char in nStr {
guard let rotatedChar = rotationMap[char] else {
return false
}
rotatedStr = String(rotatedChar) + rotatedStr
}

return rotatedStr != nStr
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1499 110
Задача: 290. Word Pattern
Сложность: easy

Дан шаблон и строка s, необходимо определить, следует ли строка s этому шаблону.

Здесь "следует" означает полное соответствие, такое что существует биекция между буквой в шаблоне и непустым словом в строке s.

Пример:
Input: pattern = "abba", s = "dog cat cat dog"
Output: true


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

1⃣Разделение строки на слова:
Разделите строку s на отдельные слова.
Если количество слов не равно длине шаблона, возвращаем false.

2⃣Создание отображений:
Создайте два словаря: один для отображения букв шаблона на слова, другой для слов на буквы шаблона.

3⃣Проверка биекции:
Пройдите по каждому символу шаблона и соответствующему слову.
Если символ уже в словаре и не соответствует текущему слову или слово уже в словаре и не соответствует текущему символу, возвращаем false.
Иначе добавляем символ и слово в словари и продолжаем проверку. Если все проверки пройдены, возвращаем true.

😎 Решение:
class Solution {
func wordPattern(_ pattern: String, _ s: String) -> Bool {
var mapChar = [Character: String]()
var mapWord = [String: Character]()
let words = s.split(separator: " ")

if words.count != pattern.count {
return false
}

for (i, word) in words.enumerated() {
let c = pattern[pattern.index(pattern.startIndex, offsetBy: i)]
let w = String(word)
if mapChar[c] == nil {
if mapWord[w] != nil {
return false
} else {
mapChar[c] = w
mapWord[w] = c
}
} else {
if mapChar[c] != w {
return false
}
}
}

return true
}
}


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