Coding & Algorithms — DE Interview PrepКод и алгоритмы — Подготовка к DE-интервью

Fast-revision cheatsheet for Data Engineering interviews. Tailored for Senior/Lead DE. Шпаргалка для быстрого повторения перед Data Engineering интервью. Заточена под Senior/Lead DE.
Code in PythonКод на Python Reason in Scala / JavaРассуждения на Scala / Java 45 min, 1–2 problems45 мин, 1–2 задачи Talk while you typeГовори во время кода
The screen tests clean correct code + clear reasoning, not exotic algorithms. Pattern-recognition > memorization. State complexity before and after coding. Ask clarifying questions first.
Скрининг проверяет чистый корректный код + понятное рассуждение, а не экзотические алгоритмы. Распознавание паттернов > зубрёжка. Формулируй сложность до и после кода. Сначала задавай уточняющие вопросы.

📐 Big-O ReasoningОценка сложности Big-O

Always state the complexity of your approach out loud, before coding, and reconfirm after. Data engineers work at scale (billions of rows/day), so connect to "what happens at 109".

Всегда формулируй сложность своего подхода вслух, до кода и подтверждай после. Дата-инженеры работают на масштабе (миллиарды строк/день), поэтому увязывай с вопросом «что будет на 109».

Complexity ladder (best → worst)Лестница сложности (лучшая → худшая)

O(1) < O(log n) < O(n) < O(n log n) < O(n²) < O(2ⁿ) < O(n!) const binary scan sort/heap nested subsets perms search dominant loops
O(1) < O(log n) < O(n) < O(n log n) < O(n²) < O(2ⁿ) < O(n!) конст. бинарный скан сортировка/ вложен. подмн-ва перестан. поиск heap доминир. циклы
n sizeSafe complexity for ~1s
n ≤ 10–12O(n!) / O(2ⁿ) — brute force / backtracking OK
n ≤ ~5,000O(n²)
n ≤ 10⁶O(n log n) — sort-based
n ≤ 10⁸+O(n) / O(log n) — single pass, hashmap, two-pointer
Размер nБезопасная сложность на ~1 сек
n ≤ 10–12O(n!) / O(2ⁿ) — brute force / backtracking приемлемы
n ≤ ~5 000O(n²)
n ≤ 10⁶O(n log n) — на основе сортировки
n ≤ 10⁸+O(n) / O(log n) — один проход, hashmap, два указателя

Reasoning rulesПравила оценки

  • Drop constants and lower-order terms: O(2n+5) → O(n).
  • Sequential code adds; nested loops multiply.
  • Amortized vs worst-case: dynamic array append is O(1) amortized, O(n) on resize. Hashmap lookup O(1) average, O(n) worst (collisions).
  • Space includes recursion stack: DFS on a tree is O(h) stack; on a skewed tree h = n.
  • Sorting is the default O(n log n) tool; if you need better, look for hashing / counting / bucketing.
  • Отбрасывай константы и младшие члены: O(2n+5) → O(n).
  • Последовательный код складывается; вложенные циклы умножаются.
  • Амортизированная vs худшая сложность: append динамического массива — O(1) амортизированно, O(n) при resize. Lookup в hashmap — O(1) в среднем, O(n) в худшем случае (коллизии).
  • Пространство включает стек рекурсии: DFS по дереву — стек O(h); на перекошенном дереве h = n.
  • Сортировка — инструмент O(n log n) по умолчанию; если нужно лучше, ищи хеширование / подсчёт / бакетинг.
"You said O(n) average for the hashmap. What's the worst case, and when does it bite in production?" → adversarial keys / hash collisions → O(n) per op; mention randomized hashing & why Java's HashMap treeifies buckets to O(log n).
«Ты сказал O(n) в среднем для hashmap. А худший случай, и когда он кусает в продакшене?» → враждебные ключи / коллизии хеша → O(n) на операцию; упомяни randomized hashing и почему Java HashMap превращает бакеты в деревья → O(log n).

🧩 Core Patterns — when to reach for whatКлючевые паттерны — когда что применять

Signal in the problemPatternTypical cost
"count / dedupe / seen before / pair sums to target"Hashmap / setO(n) time, O(n) space
Sorted array, "pair / triplet", in-placeTwo pointersO(n) after sort
"contiguous subarray/substring", "window of size k", "longest/shortest ... with constraint"Sliding windowO(n)
"top-k / k smallest / k closest / merge k / running median"Heap (priority queue)O(n log k)
"shortest path (unweighted)", "level order", "min steps"BFSO(V+E)
"connected components", "reachability", "cycle", "topological order"DFS / Union-Find / topoO(V+E)
"ancestor / path / depth / BST"Tree traversal (DFS)O(n)
"overlapping ranges / merge / meeting rooms"Intervals (sort by start)O(n log n)
"order doesn't matter but values cluster", small rangeCounting / bucket sortO(n+k)
"choices / combinations / partitions", n smallBacktrackingexponential
"min/max ways, overlapping subproblems"DP / memoizationstates × transition
Сигнал в задачеПаттернТипичная цена
«подсчитать / дедуплицировать / видели раньше / пара с суммой = target»Hashmap / setO(n) время, O(n) память
Отсортированный массив, «пара / тройка», in-placeДва указателяO(n) после сортировки
«непрерывный подмассив/подстрока», «окно размера k», «самый длинный/короткий ... с ограничением»Скользящее окноO(n)
«top-k / k наименьших / k ближайших / merge k / running median»Heap (priority queue)O(n log k)
«кратчайший путь (невзвешенный)», «level order», «минимум шагов»BFSO(V+E)
«компоненты связности», «достижимость», «цикл», «топологический порядок»DFS / Union-Find / topoO(V+E)
«предок / путь / глубина / BST»Обход дерева (DFS)O(n)
«пересекающиеся интервалы / merge / meeting rooms»Интервалы (сортировка по началу)O(n log n)
«порядок не важен, но значения кластеризуются», малый диапазонПодсчёт / bucket sortO(n+k)
«варианты / комбинации / разбиения», малое nBacktrackingэкспоненциальная
«мин/макс способов, перекрывающиеся подзадачи»DP / мемоизациясостояния × переход

Two pointers — three flavorsДва указателя — три варианта

  • Opposite ends: sorted-pair-sum, palindrome, container-with-water. Move the side that can improve the answer.
  • Same direction (fast/slow): cycle detection (Floyd), remove duplicates in place, find midpoint.
  • Read/write pointer: in-place compaction (move zeros, remove element).
  • С противоположных концов: sorted-pair-sum, палиндром, container-with-water. Двигай ту сторону, которая может улучшить ответ.
  • В одном направлении (быстрый/медленный): обнаружение цикла (Floyd), удаление дублей in-place, поиск середины.
  • Read/write указатель: in-place уплотнение (передвинуть нули, удалить элемент).

Sliding window — the templateСкользящее окно — шаблон

def window(s):
    left = 0; state = {}                 # counts/freq in window
    best = 0
    for right in range(len(s)):
        add(s[right], state)            # expand right
        while invalid(state):           # shrink from left
            remove(s[left], state); left += 1
        best = max(best, right - left + 1)
    return best
Fixed-size window: shrink by exactly one when right-left+1 > k. Variable window: shrink with a while until valid again. Mixing these up is the #1 bug.
Окно фиксированного размера: сжимай ровно на один, когда right-left+1 > k. Переменное окно: сжимай с помощью while, пока не станет валидным. Путаница здесь — самый частый баг.

BFS vs DFSBFS vs DFS

BFSDFS
StructureQueue (deque)Stack / recursion
Best forShortest path (unweighted), level orderPath existence, components, cycles, topo, backtracking
SpaceO(width)O(depth)
Shortest path?Yes (unweighted)No (not guaranteed)
BFSDFS
СтруктураQueue (deque)Stack / рекурсия
Лучше дляКратчайший путь (невзвешенный), level orderСуществование пути, компоненты, циклы, topo, backtracking
ПамятьO(ширина)O(глубина)
Кратчайший путь?Да (невзвешенный)Нет (не гарантируется)
"Why BFS not DFS for shortest path?" → BFS explores in layers, so the first time you reach a node is via the fewest edges. DFS may reach it via a longer path first. For weighted graphs use Dijkstra (heap); for negative weights Bellman-Ford.
«Почему BFS, а не DFS для кратчайшего пути?» → BFS обходит слоями, поэтому первый раз до вершины добираешься по минимуму рёбер. DFS может сначала прийти через более длинный путь. Для взвешенных графов используй Dijkstra (heap); для отрицательных весов — Bellman-Ford.

🗃️ Data Structures — costs & gotchasСтруктуры данных — цена и подводные камни

StructureAccessSearchInsertDeleteNotes
Dynamic arrayO(1)O(n)O(1)*amortO(n)append amortized O(1); insert-mid O(n)
Hashmap / setO(1) avgO(1) avgO(1) avgO(n) worst; unordered
Balanced BST / TreeMapO(log n)O(log n)O(log n)ordered; range queries, floor/ceil
Heap (binary)peek O(1)O(n)O(log n)pop O(log n)min/max, top-k, streaming median
Linked listO(n)O(n)O(1) at nodeO(1) at nodeO(1) splice if you hold the node
Stack / QueueO(1)O(1)deque is both ends O(1)
TrieO(L)O(L)O(L)prefix search; L = key length
СтруктураДоступПоискВставкаУдалениеЗаметки
Динамический массивO(1)O(n)O(1)*амортO(n)append амортизированно O(1); вставка в середину O(n)
Hashmap / setO(1) среднееO(1) среднееO(1) среднееO(n) худший случай; неупорядочены
Сбалансированное BST / TreeMapO(log n)O(log n)O(log n)упорядочено; range-запросы, floor/ceil
Heap (бинарная)peek O(1)O(n)O(log n)pop O(log n)min/max, top-k, streaming median
Связный списокO(n)O(n)O(1) у узлаO(1) у узлаO(1) splice, если держишь узел
Stack / QueueO(1)O(1)deque — с обоих концов O(1)
TrieO(L)O(L)O(L)поиск префикса; L = длина ключа

Heap mental modelМентальная модель heap

Top-k LARGEST → use a MIN-heap of size k (pop smallest when > k) Top-k SMALLEST → use a MAX-heap of size k Running MEDIAN → two heaps: max-heap (low half) + min-heap (high half), balanced
Top-k НАИБОЛЬШИХ → используй MIN-heap размера k (pop наименьший когда > k) Top-k НАИМЕНЬШИХ → используй MAX-heap размера k Running MEDIAN → две heap: max-heap (нижняя половина) + min-heap (верхняя половина), сбалансированы
Python's heapq is a min-heap only. For a max-heap, push -x. For top-k largest, keep a min-heap of size k and heappushpop.
Python heapq — это только min-heap. Для max-heap засовывай -x. Для top-k наибольших держи min-heap размера k и используй heappushpop.

Union-Find (Disjoint Set) — for connectivityUnion-Find (Disjoint Set) — для связности

def find(p, x):
    while p[x] != x:
        p[x] = p[p[x]]          # path compression
        x = p[x]
    return x

Near-O(1) per op with path compression + union by rank. Reach for it on "number of islands as a stream", "accounts merge", "redundant connection".

Почти O(1) на операцию с path compression + union by rank. Используй для «число островов в потоке», «слияние аккаунтов», «избыточное ребро».

10 Representative Problems10 типичных задач

Click to expand. Each = signal → approach → complexity → gotcha. These cover every pattern a coding screen pulls from.

Кликни, чтобы развернуть. Каждая = сигнал → подход → сложность → подводный камень. Покрывают все паттерны, которые встречаются на экране.

1Two Sumhashmapeasy

Ask: indices of two numbers summing to target.

Задача: индексы двух чисел с суммой = target.

Approach: one pass, hashmap of value → index. For each x, check if target - x seen.

Подход: один проход, hashmap значение → индекс. Для каждого x проверяй, видели ли target - x.

Complexity: O(n) time, O(n) space. Beats sort + two-pointer O(n log n) when you must return original indices.

Сложность: O(n) время, O(n) память. Выигрывает у sort + two-pointer O(n log n), когда нужно вернуть исходные индексы.

Handle duplicates and "same element twice" (check before inserting). Clarify: one solution guaranteed? negative numbers?
Обработай дубли и «тот же элемент дважды» (проверяй до вставки). Уточни: гарантированно одно решение? отрицательные числа?
2Longest Substring Without Repeating Characterssliding windowmed

Signal: "longest substring with constraint" → variable sliding window.

Сигнал: «самая длинная подстрока с ограничением» → переменное скользящее окно.

Approach: window + last-seen-index map. When char repeats inside window, jump left = max(left, last[c]+1).

Подход: окно + карта «последний-встреченный-индекс». Когда символ повторяется в окне, прыгай left = max(left, last[c]+1).

Complexity: O(n) time, O(min(n, charset)) space.

Сложность: O(n) время, O(min(n, charset)) память.

"Unicode / emoji input?" → charset size assumption changes space bound; clarify ASCII vs full Unicode.
«Unicode / эмодзи на входе?» → размер charset меняет границу по памяти; уточни ASCII vs полный Unicode.
3Merge Intervalsintervalsmed

Approach: sort by start; iterate; if cur.start <= last.end merge (last.end = max(...)), else push.

Подход: сортируй по началу; итерируй; если cur.start <= last.end мёржь (last.end = max(...)), иначе добавь.

Complexity: O(n log n) dominated by sort, O(n) output.

Сложность: O(n log n) определяется сортировкой, O(n) выход.

Edge: touching intervals [1,3],[3,5] — clarify if they merge (usually yes). Empty input. Already-overlapping nested intervals.
Граница: касающиеся интервалы [1,3],[3,5] — уточни, мёржатся ли они (обычно да). Пустой вход. Уже пересекающиеся вложенные интервалы.

Cousins: Insert Interval, Meeting Rooms II (min rooms = max concurrent → min-heap of end times, or sweep line).

Родственные задачи: Insert Interval, Meeting Rooms II (мин комнат = макс одновременных → min-heap времён окончания, или sweep line).

4Top K Frequent Elementsheap / bucketmed

Approach A: count freq (hashmap), then min-heap of size k → O(n log k).

Подход А: считай частоту (hashmap), затем min-heap размера k → O(n log k).

Approach B (better): bucket sort by frequency (index = count) → O(n).

Подход Б (лучше): bucket sort по частоте (индекс = счётчик) → O(n).

Amal anchor "This is a stream of billions of events — you can't hold all counts." → mention Count-Min Sketch / approximate heavy-hitters (Space-Saving). Great bridge to your Meta 3.6B events/day work.
Якорь Amal «Это поток миллиардов событий — все счётчики не держать.» → упомяни Count-Min Sketch / approximate heavy-hitters (Space-Saving). Отличная связь с твоей работой в Meta 3,6 млрд событий/день.
5Number of Islandsgraph BFS/DFSmed

Approach: grid = implicit graph. Scan cells; on unvisited '1', flood-fill (DFS/BFS) marking visited, increment count.

Подход: сетка = неявный граф. Сканируй клетки; на непосещённой '1' flood-fill (DFS/BFS), отмечая посещённые, увеличь счётчик.

Complexity: O(rows × cols) time & space.

Сложность: O(строк × столбцов) время и память.

Mutating input vs separate visited set — clarify if you may modify the grid. Recursion depth on huge grids → use iterative BFS to avoid stack overflow (mention this; it's a craftsmanship signal).
Мутировать вход vs отдельный visited set — уточни, можно ли модифицировать сетку. Глубина рекурсии на огромных сетках → используй итеративный BFS, чтобы не переполнить стек (упомяни это; это сигнал мастерства).
6Course Schedule (Topological Sort)graph / topomed

Signal: "can you finish given prerequisites" = detect cycle in directed graph / produce topo order.

Сигнал: «можно ли закончить при заданных prerequisite» = обнаружить цикл в направленном графе / построить topo-порядок.

Approach: Kahn's algorithm — compute in-degrees, queue of zero-indegree nodes, peel them off. If processed count < n → cycle.

Подход: алгоритм Кана — считай входящие степени, очередь узлов с нулевой степенью, снимай их. Если обработано < n → цикл.

Complexity: O(V+E).

Сложность: O(V+E).

Maps directly to DAG-based pipeline scheduling (Airflow/Dataswarm/Chronos): a cycle = an impossible dependency graph.

Прямо соответствует DAG-планированию пайплайнов (Airflow/Dataswarm/Chronos): цикл = невозможный граф зависимостей.

7Binary Tree Level-Order Traversaltree / BFSeasy–med

Approach: BFS with a queue; per level, snapshot len(queue) and process exactly that many.

Подход: BFS с очередью; на каждом уровне запомни len(queue) и обработай ровно столько.

Complexity: O(n) time, O(width) space.

Сложность: O(n) время, O(ширина) память.

Variants: zigzag (reverse alternate levels), right-side view (last node per level), max depth.

Варианты: zigzag (переворачивай чередующиеся уровни), right-side view (последний узел на уровне), max depth.

Know the 3 DFS orders cold: preorder (root,L,R), inorder (L,root,R → sorted for BST), postorder (L,R,root → cleanup/aggregation).
Знай 3 порядка DFS наизусть: preorder (корень,L,R), inorder (L,корень,R → сортировано для BST), postorder (L,R,корень → cleanup/агрегация).
8Lowest Common Ancestor (Binary Tree)tree / recursionmed

Approach: recurse; if node is p or q return node; recurse left & right; if both non-null → current is LCA; else bubble up the non-null one.

Подход: рекурсия; если узел — p или q, верни узел; рекурси left и right; если оба не-null → текущий узел — LCA; иначе всплывает не-null.

Complexity: O(n) time, O(h) stack.

Сложность: O(n) время, O(h) стек.

BST version is easier: walk down comparing values, O(h). Clarify whether it's a BST.
Версия для BST проще: иди вниз, сравнивая значения, O(h). Уточни, BST ли это.
9Merge K Sorted Listsheaphard

Approach: min-heap of the current head of each list; pop smallest, push its next.

Подход: min-heap текущих голов всех списков; pop наименьший, добавь его next.

Complexity: O(N log k) where N = total nodes, k = lists. Beats naive O(Nk).

Сложность: O(N log k), где N = всего узлов, k = списков. Выигрывает у наивного O(Nk).

Amal anchor "How does this scale to merging sorted shards from a distributed sort?" → exactly the merge step of external/distributed merge-sort; ties to Spark/MapReduce shuffle. Strong bridge for a data-eng candidate.
Якорь Amal «Как это масштабируется на мёрж отсортированных шардов из распределённой сортировки?» → в точности merge-шаг внешней/распределённой merge-sort; связывается с Spark/MapReduce shuffle. Сильный мост для дата-инженера.
10Kth Largest Element / Quickselectsort / heap / partitionmed

Approach A: min-heap of size k → O(n log k), easy, streaming-friendly.

Подход А: min-heap размера k → O(n log k), просто, поддерживает streaming.

Approach B: Quickselect (partition like quicksort, recurse one side) → O(n) average, O(n²) worst.

Подход Б: Quickselect (partition как в quicksort, рекурси одну сторону) → O(n) в среднем, O(n²) худший случай.

Quickselect worst case on adversarial/sorted input → randomize the pivot. State the trade-off: heap is robust & streaming; quickselect is faster average but needs all data in memory.
Quickselect худший случай на враждебном/отсортированном входе → рандомизируй pivot. Формулируй компромисс: heap — надёжно & streaming; quickselect — быстрее в среднем, но требует все данные в памяти.
Bonus to skim: Valid Parentheses (stack), Product of Array Except Self (prefix/suffix, no division), Group Anagrams (hashmap with sorted-key/char-count key), Binary Search + variants (lower/upper bound, rotated array), Move Zeroes (read/write pointer).
Бонусом пробеги: Valid Parentheses (stack), Product of Array Except Self (prefix/suffix, без деления), Group Anagrams (hashmap с sorted-key/char-count-ключом), Binary Search + варианты (lower/upper bound, rotated array), Move Zeroes (read/write pointer).

🃏 Flip-to-Reveal Self-QuizСамопроверка с переворотом

Tap a card to flip. Drill these until the answer is instant.

Кликни карточку, чтобы перевернуть. Повторяй, пока ответ не станет мгновенным.

QWhen do you pick a hashmap over sorting?tap to flip
When you need O(n) lookups/dedup/counting and don't need order. Sorting gives O(n log n) but enables two-pointer, range queries, and ordered output.
ВКогда выбираешь hashmap вместо сортировки?кликни
Когда нужны O(n) поиски/дедуп/подсчёт и не нужен порядок. Сортировка даёт O(n log n), но включает два указателя, range-запросы и упорядоченный вывод.
QTop-k LARGEST: which heap and what size?tap to flip
A min-heap of size k. Push each element; if size > k, pop the smallest. The heap ends holding the k largest; root is the k-th largest. O(n log k).
ВTop-k НАИБОЛЬШИХ: какая heap и какого размера?кликни
Min-heap размера k. Добавляй каждый элемент; если размер > k, pop наименьший. В итоге heap держит k наибольших; корень — k-й наибольший. O(n log k).
QBFS or DFS for shortest path in an unweighted graph?tap to flip
BFS. Layer-by-layer means first arrival = fewest edges. Weighted → Dijkstra (heap). Negative weights → Bellman-Ford.
ВBFS или DFS для кратчайшего пути в невзвешенном графе?кликни
BFS. Слой за слоем означает первый приход = минимум рёбер. Взвешенный → Dijkstra (heap). Отрицательные веса → Bellman-Ford.
QInorder traversal of a BST gives you...?tap to flip
Values in sorted ascending order. Useful for "kth smallest in BST", validating a BST, and range queries.
ВInorder обход BST даёт тебе...?кликни
Значения в отсортированном порядке по возрастанию. Полезно для «k-й наименьший в BST», валидации BST и range-запросов.
QFixed vs variable sliding window — how do you shrink?tap to flip
Fixed: shrink by exactly one when size > k (if). Variable: shrink with a while until the window is valid again.
ВФиксированное vs переменное окно — как сжимать?кликни
Фиксированное: сжимай ровно на один, когда размер > k (if). Переменное: сжимай с помощью while, пока окно не станет валидным.
QHashmap worst-case lookup & why?tap to flip
O(n) from hash collisions (all keys in one bucket). Mitigations: good hash + randomization; Java treeifies long buckets to O(log n).
ВHashmap худший случай поиска и почему?кликни
O(n) из-за коллизий хеша (все ключи в одном бакете). Лечение: хороший хеш + рандомизация; Java превращает длинные бакеты в деревья → O(log n).
QDetect a cycle in a directed graph?tap to flip
Kahn's topo sort (if processed < n → cycle), or DFS with 3-color (white/gray/black); a back-edge to a gray node = cycle.
ВОбнаружить цикл в направленном графе?кликни
Topo-сортировка Кана (если обработано < n → цикл), или DFS с 3 цветами (белый/серый/чёрный); обратное ребро к серому узлу = цикл.
QQuickselect average vs worst, and the fix?tap to flip
Average O(n), worst O(n²) on bad pivots. Fix: randomized / median-of-medians pivot. Heap alternative is O(n log k) but robust.
ВQuickselect среднее vs худший случай, и как лечить?кликни
Среднее O(n), худший O(n²) на плохих pivot. Лечение: рандомизированный / median-of-medians pivot. Heap альтернатива O(n log k), но надёжнее.
QStreaming median — what structure?tap to flip
Two heaps: a max-heap for the lower half and a min-heap for the upper half, kept balanced (sizes differ by ≤1). Median = root(s). O(log n) insert.
ВStreaming median — какая структура?кликни
Две heap: max-heap для нижней половины и min-heap для верхней половины, сбалансированы (размеры отличаются ≤1). Медиана = корень(и). O(log n) вставка.
QSpace cost of recursive DFS?tap to flip
O(h) call-stack (tree height / recursion depth). On a skewed tree h = n → risk of stack overflow; convert to iterative with an explicit stack.
ВСтоимость по памяти рекурсивного DFS?кликни
O(h) стек вызовов (высота дерева / глубина рекурсии). На перекошенном дереве h = n → риск переполнения стека; переводи в итеративный с явным стеком.

🐍 Code in Python · Reason in Scala / JavaКод на Python · Рассуждения на Scala / Java

Many DE roles require Java or Scala. You'll likely code in Python (fastest for you) but they may ask you to reason in Scala/Java idioms. Be fluent in the mapping.

Многие DE-роли требуют Java или Scala. Ты, скорее всего, кодишь на Python (для тебя быстрее), но могут попросить рассуждать на идиомах Scala/Java. Будь бегл в маппинге.

ConceptPythonScalaJava
Hashmapdict / defaultdictmutable.Map / MapHashMap
Setsetmutable.SetHashSet
Min-heapheapqmutable.PriorityQueue (max by default; reverse Ordering)PriorityQueue
Queue/Dequecollections.dequemutable.Queue / ArrayDequeArrayDeque
Ordered map—(use sortedcontainers)TreeMap / SortedMapTreeMap
Countercollections.CountergroupBy(identity).mapValues(_.size)manual merge(k,1,Integer::sum)
КонцепцияPythonScalaJava
Hashmapdict / defaultdictmutable.Map / MapHashMap
Setsetmutable.SetHashSet
Min-heapheapqmutable.PriorityQueue (макс по умолчанию; reverse Ordering)PriorityQueue
Queue/Dequecollections.dequemutable.Queue / ArrayDequeArrayDeque
Ordered map—(используй sortedcontainers)TreeMap / SortedMapTreeMap
Countercollections.CountergroupBy(identity).mapValues(_.size)вручную merge(k,1,Integer::sum)
Talking points to drop: Scala immutability by default & pure functions (matters for Spark/Flink correctness & testability); pattern matching for clean tree/graph recursion; Java's HashMap treeify-on-collision; the JVM boxing cost of Integer vs int in hot loops.
Тезисы для упоминания: Scala immutability по умолчанию & чистые функции (важно для корректности & тестируемости Spark/Flink); pattern matching для чистой рекурсии деревьев/графов; Java HashMap treeify-on-collision; цена boxing JVM — Integer vs int в горячих циклах.

Scala idiom worth saying out loudИдиома Scala, которую стоит произнести вслух

// pattern matching makes tree recursion clean & total
def sum(t: Tree): Int = t match {
  case Leaf(v)        => v
  case Node(l, _, r)  => sum(l) + sum(r)
}
Amal anchor (honest) Your recent stack is Python/SQL. If asked to write idiomatic Scala/Flink live, lean on your real Scala/Spark-on-Hadoop work at Front Tier (default-prediction training pipeline) and your Kafka ingestion at IU Group. Be candid: "I'd write the algorithm in Python for speed here, and I can walk through the Scala equivalent — my production Scala was the Spark training pipeline at Front Tier."
Якорь Amal (честно) Твой недавний стек — Python/SQL. Если попросят написать идиоматичный Scala/Flink вживую, опирайся на реальную работу Scala/Spark-on-Hadoop во Front Tier (training pipeline для default-prediction) и Kafka ingestion в IU Group. Будь откровенен: «Я бы написал алгоритм на Python для скорости здесь, и могу пройтись по эквиваленту на Scala — мой продакшен Scala был в Spark training pipeline во Front Tier».

In-Interview Checklist (UMPIRE)Чеклист на интервью (UMPIRE)

  1. U — Understand: restate the problem; ask about input size, types, nulls, duplicates, sorted?, empty, negatives, Unicode, in-place allowed?
  2. M — Match: name the pattern out loud ("this looks like a sliding-window / hashmap problem").
  3. P — Plan: describe the approach & state complexity before coding. Mention the brute force, then the optimization.
  4. I — Implement: write clean code, talk through it, meaningful names, no premature golfing.
  5. R — Review: dry-run a small example AND an edge case (empty, single element, all same).
  6. E — Evaluate: restate final time/space; discuss trade-offs, scaling to billions, how you'd test it.
  1. U — Understand (Понимание): переформулируй задачу; спроси про размер входа, типы, null, дубли, отсортирован?, пуст, отрицательные, Unicode, можно ли in-place?
  2. M — Match (Сопоставление): назови паттерн вслух («это похоже на sliding-window / hashmap-задачу»).
  3. P — Plan (План): опиши подход & сформулируй сложность до кода. Упомяни brute force, затем оптимизацию.
  4. I — Implement (Реализация): пиши чистый код, говори, что делаешь, осмысленные имена, не гольфь преждевременно.
  5. R — Review (Проверка): прогони вручную маленький пример И граничный случай (пусто, один элемент, все одинаковые).
  6. E — Evaluate (Оценка): переформулируй финальное время/память; обсуди компромиссы, масштабирование на миллиарды, как бы ты тестировал.
Senior candidates stand out with craftsmanship & testing. Proactively say "here are the unit tests I'd write" — happy path, empty, single, duplicates, large/overflow, adversarial. That alone differentiates senior candidates.
Senior-кандидаты выделяются мастерством & тестированием. Проактивно скажи «вот юнит-тесты, которые я бы написал» — happy path, пусто, один, дубли, большое/переполнение, враждебный вход. Это само по себе отличает senior-кандидатов.
Common failure modes to self-watch: off-by-one in window/binary-search bounds; not handling empty input; integer overflow (matters in Java/Scala — use long); mutating while iterating; forgetting the visited set in graph traversal.
Частые провалы, за которыми следи: off-by-one в границах окна/бинарного поиска; не обработал пустой вход; переполнение integer (важно в Java/Scala — используй long); мутируешь во время итерации; забыл visited set в обходе графа.
If stuck: state the brute force first (always have one), then optimize. A correct O(n²) beats a broken O(n). Think aloud — silence reads as being stuck.
Если застрял: сначала сформулируй brute force (он всегда есть), затем оптимизируй. Правильный O(n²) выигрывает у сломанного O(n). Думай вслух — молчание читается как «застрял».