Irbisa · Шпаргалка
Live coding на Swift
Big O, хеширование, стек и очередь, два указателя, скользящее окно, бинарный поиск, связные списки, деревья, LRU-кэш, кучи и DP на Swift
Что такое нотация Big O и как на лайвкодинге назвать сложность своего решения по времени и по памяти?
Как
SetилиDictionaryпревращают two-sum, поиск дубликатов или проверку на анаграмму из O(n²) в O(n) в Swift?func hasDuplicate(_ xs: [Int]) -> Bool { var seen = Set<Int>() for x in xs { if !seen.insert(x).inserted { return true } // inserted is false for a repeat } return false…Как реализовать стек и очередь на Swift и почему
Array.removeFirst()плохо подходит для извлечения из очереди?struct Stack<Element> { private var items: [Element] = [] mutating func push(_ x: Element) { items.append(x) } // amortized O(1) mutating func pop() -> Element? { items.popLast() } // O(1), nil when empty var top: Element? { items.last } var isEmpty: Bool { items.isEmpty }…Лайвкодинг: проверьте, что строка из скобок вроде
"([]{})"сбалансирована. Какую структуру вы возьмёте и какие входы ломают наивное решение?func isBalanced(_ s: String) -> Bool { let openerFor: [Character: Character] = [")": "(", "]": "[", "}": "{"] var stack: [Character] = [] for c in s { if "([{".contains(c) { stack.append(c)…Лайвкодинг: слейте два отсортированных массива в один отсортированный за O(n + m), не вызывая
sorted(). Какие есть пограничные случаи?func merge<T: Comparable>(_ a: [T], _ b: [T]) -> [T] { var result: [T] = [] result.reserveCapacity(a.count + b.count) // one allocation var i = 0, j = 0 while i < a.count && j < b.count { if a[i] <= b[j] { // <= takes a's element first on a tie: stable…Лайвкодинг: напишите свои
mapиreduceкак расширенияSequence. Что дают сигнатуре дженерики иrethrows?extension Sequence { func myMap<T>(_ transform: (Element) throws -> T) rethrows -> [T] { var result: [T] = [] result.reserveCapacity(underestimatedCount) // a lower bound, often 0: only a hint for element in self { result.append(try transform(element))…Как
Dictionary(grouping:by:),reduce(into:)иuniquingKeysWith:решают «сгруппировать анаграммы» и «посчитать слова» и в чём ловушка обычногоreduce?let words = ["eat", "tea", "tan", "ate", "nat", "bat"] // Group anagrams: the sorted letters are the shared keylet groups = Dictionary(grouping: words) { String($0.sorted()) }// ["aet": ["eat", "tea", "ate"], "ant": ["tan", "nat"], "abt": ["bat"]]…Найдите баг: эта проверка на палиндром отвечает правильно, но на строке из 100 000 символов работает секунды.
func isPalindrome(_ s: String) -> Bool { var left = 0 var right = s.count - 1 while left < right { let l = s[s.index(s.startIndex, offsetBy: left)] let r = s[s.index(s.startIndex, offsetBy: right)] if l != r { return false } left += 1 right -= 1 } return true}Какой алгоритм использует
sort()в Swift, стабилен ли он и как отсортировать пользователей по убыванию очков, а затем по имени?import Foundation struct User { let name: String let score: Int}…Лайвкодинг: объедините пересекающиеся слоты вроде
[1, 3], [2, 6], [8, 10]. Зачем сначала сортировать и нужно ли сливать соприкасающиеся[1, 3]и[3, 5]?func merge(_ slots: [ClosedRange<Int>]) -> [ClosedRange<Int>] { let sorted = slots.sorted { $0.lowerBound < $1.lowerBound } // O(n log n) var result: [ClosedRange<Int>] = [] for slot in sorted { if let last = result.last, slot.lowerBound <= last.upperBound { // overlaps or touches the last merged slot: extend it, keeping the later end…Как техники двух указателей и скользящего окна превращают перебор за O(n²) в O(n)? Покажите на самой длинной подстроке без повторяющихся символов.
// Two pointers on a sorted array: indices of a pair with the given sum, O(n)func pair(in sorted: [Int], sum target: Int) -> (Int, Int)? { var l = 0, r = sorted.count - 1 while l < r { let sum = sorted[l] + sorted[r] if sum == target { return (l, r) }…Этот бинарный поиск на одних входах падает, а на других никогда не возвращается. Что с ним не так и какой инвариант цикла делает его правильным?
func indexOf(_ target: Int, in a: [Int]) -> Int? { var lo = 0 var hi = a.count while lo <= hi { let mid = (lo + hi) / 2 if a[mid] == target { return mid } if a[mid] < target { lo = mid } else { hi = mid - 1 } } return nil}Лайвкодинг: разверните односвязный список на месте. Продолжение: может ли освобождение списка из миллиона узлов переполнить стек в Swift, а глубокого дерева?
final class Node<T> { var value: T var next: Node? init(_ value: T, next: Node? = nil) { self.value = value self.next = next…Как обойти бинарное дерево в глубину и в ширину на Swift и какой обход подходит для «максимальной глубины», а какой для «обхода по уровням»?
final class TreeNode { let val: Int var left: TreeNode? var right: TreeNode? init(_ val: Int, _ left: TreeNode? = nil, _ right: TreeNode? = nil) { self.val = val…Лайвкодинг: реализуйте LRU-кэш с
getиputза O(1). Какие две структуры вы совместите и почему одногоDictionaryнедостаточно?final class LRUCache<Key: Hashable, Value> { private final class Node { let key: Key? // nil only in the two sentinels var value: Value? var next: Node? weak var prev: Node? // weak: neighbours must not retain each other…Как распознать задачу на динамическое программирование и как перейти от простой рекурсии к мемоизации и к таблице снизу вверх на Swift?
// House robber: the most money from houses 0...i without robbing two neighbours.// best(i) = max(best(i - 1), best(i - 2) + nums[i]): skip house i, or rob it // 1. Plain recursion: O(2^n), the same i is solved again and againfunc robNaive(_ nums: [Int], _ i: Int) -> Int { if i < 0 { return 0 }…В стандартной библиотеке Swift нет кучи. Как найти 100 самых частых слов в большом тексте и сколько стоит каждый подход?
typealias Entry = (word: Substring, count: Int) // A min-heap by count in a plain array: the children of i sit at 2i + 1 and 2i + 2func siftDown(_ heap: inout [Entry], from start: Int) { var i = start while true {…Фича-модули объявляют, от каких модулей зависят. Как вычислить порядок сборки топологической сортировкой и как тот же проход находит цикл?
struct CycleError: Error { let stuck: [String] } /// deps[module] lists the modules that must be built before it.func buildOrder(_ deps: [String: [String]]) -> Result<[String], CycleError> { var waitingOn: [String: Int] = [:] // module -> dependencies not built yet var dependents: [String: [String]] = [:] // dependency -> modules waiting for it…