0Pricing
DSA Interview Prep · Урок

Шпаргалка по распознаванию шаблонов

Сопоставьте 15 распространённых признаков задач — отсортированный массив, необходимость получить все комбинации, максимизация значения при ограничении и другие — с алгоритмическими шаблонами, которые решают их быстрее всего

«Шпаргалка по распознаванию шаблонов» — бесплатный урок DSA Interview Prep на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения DSA Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс DSA Interview Prep содержит 4 уроков всего.

Игра на распознавание паттернов за 60 секунд

На реальном собеседовании у Вас есть примерно 60 секунд после прочтения задачи, чтобы определить подходящий алгоритмический паттерн, прежде чем интервьюер ожидает от Вас начала написания кода. Это самый важный навык, который следует развивать: важно не заучивать реализации, а распознавать, к какому инструменту обратиться.

Распознавание паттернов формируется за счёт сопоставления признаков задачи (слов и ограничений в её условии) с известными семействами алгоритмов. После определения паттерна реализация превращается в заполнение шаблона. Этот урок представляет собой систематическую шпаргалку по 15 наиболее распространённым признакам задач и соответствующим им паттернам.

# The recognition process
recognition_steps = [
    '1. Read the problem once fully (do not start coding)',
    '2. Identify the data structure: array, string, tree, graph, matrix?',
    '3. Identify the ask: find min/max, count ways, enumerate, detect cycle...?',
    '4. Note the constraint: n<=20 (bitmask), sorted (binary search), DAG (topo sort)?',
    '5. Map signal -> pattern',
    '6. State the pattern and complexity to the interviewer before coding',
    '7. Handle edge cases mentally before writing',
]
for step in recognition_steps:
    print(step)

Признаки 1–3: паттерны для массивов и строк

Наиболее частые признаки задач для массивов и строк:

  • Отсортированный массив + поиск заданного значения → Бинарный поиск O(log n)
  • Поиск пары или тройки с заданной суммой → Два указателя O(n), если массив отсортирован, хеш-таблица O(n), если он не отсортирован
  • Самый длинный или короткий подмассив либо подстрока, удовлетворяющие условию → Скользящее окно O(n)
  • Максимальная или минимальная сумма непрерывного подмассива → Алгоритм Кадане O(n)
  • Обнаружение дубликатов → Хеш-множество O(n) или сортировка O(n log n)

Если массив отсортирован, всегда сначала рассматривайте бинарный поиск. Несортированный массив + целевая сумма + O(n) = почти всегда хеш-таблица для поиска дополнения.

# Quick recognition: array/string signals
signals = [
    ('Sorted array, find element',           'Binary search O(log n)'),
    ('Find two elements summing to K',        'Sort+two-ptr O(n log n) or hash O(n)'),
    ('Longest subarray with property P',      'Sliding window (variable size) O(n)'),
    ('Max sum contiguous subarray',           'Kadane algorithm O(n)'),
    ('Anagram/permutation check',             'Frequency map (Counter) O(n)'),
    ('Contains duplicate',                    'Hash set O(n)'),
    ('Merge two sorted arrays/lists',         'Two pointers O(n+m)'),
    ('Rotate / shift array',                  'Reverse trick O(n) in-place'),
    ('Next permutation',                      'Find rightmost ascent + swap + reverse'),
    ('Maximum product subarray',              'Track max and min (handles negatives)'),
]
for signal, pattern in signals:
    print(f'{signal:45s} => {pattern}')

Признаки 4–6: паттерны для деревьев и графов

Признаки задач для деревьев и графов и соответствующие им паттерны:

  • Обход по уровням / кратчайший путь во невзвешенном графе → BFS с двусторонней очередью O(V+E)
  • Исследование всех путей / обнаружение циклов / порядок DFS → Рекурсивный или итеративный DFS O(V+E)
  • BST + свойства симметричного обхода (k-й элемент, отсортированный порядок) → DFS с симметричным обходом O(n)
  • Наименьший общий предок → Рекурсивный спуск с отслеживанием пути O(n)
  • Связные компоненты / объединение двух групп → DSU O(n × alpha(n))
# Tree/graph signal recognition
tree_graph_signals = [
    ('Level-order / minimum depth / word ladder',    'BFS with deque'),
    ('All paths / path sum / all permutations tree',  'DFS recursive'),
    ('Cycle detection (undirected)',                  'DFS with parent / DSU'),
    ('Cycle detection (directed) / course schedule', 'DFS three-color / Kahn topo sort'),
    ('Shortest path weighted graph',                  'Dijkstra (non-neg) / Bellman-Ford (neg)'),
    ('All-pairs shortest path',                       'Floyd-Warshall O(V^3)'),
    ('Topological order',                             'Kahn BFS topo sort'),
    ('Min spanning tree',                             'Kruskal (DSU) / Prim (heap)'),
    ('Dynamic connectivity / union-find',             'DSU path compression + union by rank'),
    ('Autocomplete / prefix search',                  'Trie'),
    ('BST kth smallest / range sum',                  'In-order DFS'),
]
for signal, pattern in tree_graph_signals:
    print(f'{signal:50s} => {pattern}')

Признаки 7–9: признаки динамического программирования

Признаки DP труднее всего распознавать. Ищите следующие ключевые слова:

  • «Количество способов...» → Подсчёт с помощью DP (складывайте количества для подзадач)
  • «Минимальная или максимальная стоимость достижения...» → Оптимизационный DP (беритe минимум или максимум из решений подзадач)
  • «Можно ли достичь...» (проверка выполнимости) → Логический DP (OR от решений подзадач)
  • Подзадача определяется двумя индексами строк → Двумерный DP (LCS, расстояние редактирования)
  • Выбор или пропуск элементов при ограничении вместимости → Рюкзачный DP
  • Оптимальная подструктура + перекрывающиеся подзадачи → Проверьте дерево рекурсии на повторяющиеся вызовы → DP
# DP signal recognition
dp_signals = [
    ('Number of ways to climb stairs / decode string',  '1D DP (Fibonacci-like)'),
    ('Minimum cost to reach end / coin change',          '1D DP (greedy fails)'),
    ('Longest increasing subsequence',                   '1D DP O(n^2) or patience sort O(n log n)'),
    ('Longest common subsequence of two strings',        '2D DP O(mn)'),
    ('Edit distance between two strings',                '2D DP O(mn) (LCS variant)'),
    ('Partition array into two equal subsets',           '0/1 knapsack boolean DP'),
    ('Fill knapsack with max value under weight limit',  '0/1 knapsack optimisation DP'),
    ('Burst balloons / matrix chain multiplication',     'Interval DP'),
    ('Palindrome partitioning minimum cuts',             'Interval DP + prefix palindrome'),
    ('Rob houses in circle',                             '1D DP × 2 (linear sub-problems)'),
]
for signal, pattern in dp_signals:
    print(f'{signal:55s} => {pattern}')

Признаки 10–12: признаки задач с кучами, стеками и жадными алгоритмами

Признаки задач с кучами, монотонным стеком и жадными алгоритмами:

  • K лучших элементов / k-й по величине или наименьший элемент → Куча (минимальная куча для K наибольших элементов, максимальная куча для k-го наименьшего) O(n log k)
  • Медиана в потоке → Две кучи (максимальная куча меньшей половины + минимальная куча большей половины)
  • Следующий больший или меньший элемент → Монотонный стек O(n)
  • Прямоугольник с максимальной площадью / задача о накоплении воды → Монотонный стек O(n)
  • Планирование интервалов / максимизация числа непересекающихся интервалов → Жадный алгоритм (сортировка по времени окончания)
# Heap / stack / greedy signals
heap_stack_greedy = [
    ('Top-K frequent elements',               'Min-heap size K: O(n log k)'),
    ('Kth largest in array',                   'Max-heap pop K times: O(n + k log n)'),
    ('Streaming median',                       'Two heaps (max + min): O(log n) per insert'),
    ('Merge K sorted lists',                   'Min-heap of (val, list_idx): O(n log k)'),
    ('Next greater element',                   'Monotonic decreasing stack: O(n)'),
    ('Largest rectangle in histogram',         'Monotonic increasing stack: O(n)'),
    ('Sliding window maximum',                 'Monotonic decreasing deque: O(n)'),
    ('Trapping rain water',                    'Two pointers OR monotonic stack: O(n)'),
    ('Jump game reachability / minimum jumps', 'Greedy range expansion: O(n)'),
    ('Merge overlapping intervals',            'Sort by start, linear scan: O(n log n)'),
    ('Gas station circular',                   'Greedy: start from reset point: O(n)'),
    ('Task scheduler with cooldown',           'Greedy: sort by frequency: O(n log n)'),
]
for signal, pattern in heap_stack_greedy:
    print(f'{signal:45s} => {pattern}')

Признаки 13–15: поиск с возвратом и побитовые операции

Признаки задач на поиск с возвратом и побитовые операции:

  • Сгенерировать все подмножества / перестановки / сочетания → Поиск с возвратом O(2^n или n!)
  • Удовлетворение ограничений (задача о N ферзях, судоку) → Поиск с возвратом и отсечениями
  • Найти один пропущенный или уникальный элемент → XOR O(n), O(1) по памяти
  • Перебрать все подмножества небольшого множества (n ≤ 20) → Перебор 2^n вариантов с помощью битовой маски
  • Подсчёт установленных битов / проверка степени двойки → Битовые приёмы (n & (n-1))
  • DP со сжатием состояний для небольшого множества → DP с битовой маской O(2^n × n)
# Backtracking and bit signals
bt_bit_signals = [
    ('Generate all subsets of array',              'Backtracking O(n * 2^n) / bitmask'),
    ('Generate all permutations',                  'Backtracking O(n * n!)'),
    ('Combination sum with target',                'Backtracking with pruning'),
    ('Word search in grid',                        'Backtracking DFS on grid O(m*n*4^L)'),
    ('N-queens placement',                         'Backtracking with column/diag sets'),
    ('Find single unique element (all others x2)', 'XOR all: O(n) O(1)'),
    ('Missing number in 0..n',                     'XOR or sum formula: O(n) O(1)'),
    ('Count set bits in n',                        'n &= n-1 loop or DP O(n)'),
    ('Check power of two',                         'n > 0 and n & (n-1) == 0'),
    ('Travelling salesman (n<=20)',                'Bitmask DP O(2^n * n^2)'),
    ('Number with max XOR in array',               'Trie on binary representation'),
]
for signal, pattern in bt_bit_signals:
    print(f'{signal:50s} => {pattern}')

Анализ ограничений: о чём говорит N

Ограничение на размер входных данных n напрямую подсказывает допустимую сложность по времени, а значит, и семейство алгоритмов:

  • n ≤ 20: допустима O(2^n) или O(n!) — DP с битовой маской, поиск с возвратом
  • n ≤ 500: допустима O(n³) — алгоритм Флойда—Уоршелла, переборный DP
  • n ≤ 5000: допустима O(n²) — наивный DP, квадратичная сортировка
  • n ≤ 10^6: необходима O(n log n) — сортировка слиянием, куча, бинарный поиск
  • n ≤ 10^8: необходима O(n) — два указателя, скользящее окно, линейный DP

Этот анализ ограничений должен быть Вашим первым шагом после прочтения задачи — до выбора алгоритма.

# Constraint -> acceptable complexity -> algorithm family
complexity_map = [
    ('n <= 20',      'O(2^n) or O(n!)',  'Bitmask DP, backtracking/permutations'),
    ('n <= 500',     'O(n^3)',            'Floyd-Warshall, cubic DP, brute force'),
    ('n <= 5000',    'O(n^2)',            'Quadratic DP, bubble/insertion sort'),
    ('n <= 100000',  'O(n log n)',         'Merge sort, heap, binary search, topo sort'),
    ('n <= 1000000', 'O(n)',              'Linear DP, two pointers, sliding window, hash'),
    ('n <= 10^8',    'O(n) tight',        'Only simplest O(n) — no large constants'),
    ('n <= 10^18',   'O(log n) or O(1)', 'Math / number theory, binary search on answer'),
]
print(f'{'Constraint':15s} {'Complexity':15s} {'Algorithm Family'}')
print('-'*70)
for constraint, complexity, algorithms in complexity_map:
    print(f'{constraint:15s} {complexity:15s} {algorithms}')

Задача → паттерн: блиц-практика

Отрабатывайте это соответствие, пока оно не станет автоматическим. Читайте описание каждой задачи и определяйте паттерн до просмотра решения. Скорость важна: на собеседовании Вы должны определить паттерн менее чем за 60 секунд:

  1. «Дан отсортированный массив; определите, есть ли в нём два элемента с суммой K»
  2. «Дано дерево; найдите его диаметр (самый длинный путь между любыми двумя узлами)»
  3. «Даны n задач с интервалом ожидания k; найдите минимальное число интервалов CPU»
  4. «Дана строка; найдите самую длинную палиндромную подстроку»
  5. «Даны числа от 1 до n, одно из которых пропущено; найдите пропущенное число»
# Quick-fire pattern recognition answers
problems = [
    ('Sorted array: two elements sum to K',
     'Two pointers (left from start, right from end): O(n)'),
    ('Tree diameter (longest path)',
     'DFS returning (height, max_diameter) pair: O(n)'),
    ('Task scheduler with cooldown k',
     'Greedy: (max_freq - 1)*(k+1) + count_of_max_freq: O(n log n)'),
    ('Longest palindromic substring',
     'Expand around centre OR Manacher: O(n^2) or O(n)'),
    ('Missing number in 1..n',
     'XOR all indices and values: O(n) O(1)'),
    ('Number of islands in binary grid',
     'BFS/DFS flood fill counting connected components: O(m*n)'),
    ('Decode string like 3[a2[bc]] -> aaabcbcaabcbc',
     'Stack to handle nested brackets: O(n)'),
    ('Valid parentheses [(){[]}]',
     'Stack push open, pop+match on close: O(n)'),
]
for problem, solution in problems:
    print(f'Q: {problem}\nA: {solution}\n')

Тревожные признаки: когда паттерн не срабатывает

Даже опытные инженеры поначалу выбирают неверный паттерн. Распознавайте следующие признаки того, что текущий подход неверен, и меняйте его:

  • Ваш алгоритм O(n²) проходит небольшие тесты, но превышает лимит времени на больших входных данных → нужна хеш-таблица, бинарный поиск или монотонная структура
  • Ваш жадный алгоритм не работает на контрпримере → попробуйте DP
  • Пространство состояний Вашего DP слишком велико → поищите доказательство жадного решения или более удачное определение состояния
  • BFS выдаёт неправильный ответ → проверьте, не нужен ли Вам алгоритм Дейкстры для взвешенного графа вместо BFS для невзвешенного
  • Вы получаете исключения из-за нулевого указателя → добавьте базовые случаи и проверки граничных случаев до реализации
# Red flags and recovery strategies
red_flags = [
    ('TLE on large n',               'Check complexity; switch from O(n^2) to O(n log n) or O(n)'),
    ('WA with greedy',               'Find a counter-example; switch to DP or prove exchange arg'),
    ('DP table huge',                'State compression (bitmask/rolling array) or different state'),
    ('BFS gives wrong shortest path', 'Check if edges have weights; use Dijkstra instead'),
    ('Stack overflow in recursion',  'Add memoisation or convert to iterative with explicit stack'),
    ('Off-by-one in binary search',  'Use half-open intervals [lo, hi); verify with 2-element test'),
    ('DSU wrong answer',             'Check 0-indexed vs 1-indexed; check union direction'),
    ('Backtracking TLE',             'Add pruning conditions; ensure undo step is correct'),
]
print('Pattern | Recovery')
print('-'*70)
for flag, recovery in red_flags:
    print(f'{flag:40s} => {recovery}')

Как объяснять распознавание паттернов на собеседованиях

На собеседованиях объяснение распознанного паттерна демонстрирует Вашу компетентность и даёт интервьюеру возможность направить Вас, если Вы движетесь не в том направлении. Используйте следующую структуру:

  1. «Я вижу, что массив отсортирован, поэтому думаю о бинарном поиске...»
  2. «В задаче требуется найти максимальный подмассив, а это классическая задача для алгоритма Кадане...»
  3. «Нам нужны все возможные подмножества, что указывает на поиск с возвратом и дерево рекурсии...»
  4. «Ограничение n ≤ 20 говорит мне, что 2^n = 1 млн допустимо, поэтому может подойти DP с битовой маской...»

После того как Вы назвали паттерн, укажите сложность по времени и памяти, прежде чем написать хотя бы одну строку кода. Это показывает, что Вы думаете об эффективности до начала реализации.

# Interview communication template
def communicate_approach(problem, pattern, time_complexity, space_complexity, edge_cases):
    print(f'Problem: {problem}')
    print(f'Pattern: {pattern}')
    print(f'Time: {time_complexity}, Space: {space_complexity}')
    print(f'Edge cases to handle: {", ".join(edge_cases)}')
    print()

# Example communications
communicate_approach(
    problem='Find longest substring without repeating characters',
    pattern='Sliding window with a set tracking current window characters',
    time_complexity='O(n)',
    space_complexity='O(min(n, alphabet_size))',
    edge_cases=['empty string', 'all same characters', 'all unique characters']
)

communicate_approach(
    problem='Given sorted matrix, find if target exists',
    pattern='Binary search or staircase search (top-right corner): eliminate row or column each step',
    time_complexity='O(m + n)',
    space_complexity='O(1)',
    edge_cases=['empty matrix', 'single element', 'target at corners']
)

Формирование словаря распознавания паттернов

Быстрее всего распознавание паттернов развивается при решении задач тематическими подборками, а не в случайном порядке. Посвятите одну неделю только задачам со скользящим окном. Затем перейдите к задачам на два указателя. После этого решайте задачи на DP. Решение 20 задач одного типа быстро развивает интуицию, необходимую для мгновенного распознавания такого паттерна.

После каждой задачи записывайте однострочную «заметку о паттерне»: признак задачи и паттерн, который он подсказал. Составьте собственную шпаргалку. Решив 200 задач тематическими подборками, Вы будете распознавать около 90% задач на собеседованиях менее чем за 30 секунд, а оставшиеся 10% требуют тщательного анализа даже от опытных инженеров.

# Personal pattern note template
pattern_notes = [
    {'signal': 'sorted array + two sum',     'pattern': 'two pointers',          'example': 'LC 167 Two Sum II'},
    {'signal': 'longest X without repeating', 'pattern': 'sliding window + set',  'example': 'LC 3 Longest Substring'},
    {'signal': 'max sum subarray',            'pattern': 'Kadane',                'example': 'LC 53 Max Subarray'},
    {'signal': 'permutations/subsets',        'pattern': 'backtracking',          'example': 'LC 46 Permutations'},
    {'signal': 'tree path sum',               'pattern': 'DFS with accumulator', 'example': 'LC 112 Path Sum'},
    {'signal': 'course schedule',             'pattern': 'Kahn topo sort',        'example': 'LC 207 Course Schedule'},
    {'signal': 'top-K elements',              'pattern': 'min-heap size K',       'example': 'LC 215 Kth Largest'},
]
print(f'{'Signal':40s} {'Pattern':30s} {'Example'}')
print('-'*90)
for note in pattern_notes:
    print(f'{note["signal"]:40s} {note["pattern"]:30s} {note["example"]}')

Быстрая проверка

Проверьте, насколько хорошо Вы усвоили изложенные в этом уроке концепции курса «Структуры данных и алгоритмы — подготовка к собеседованию по программированию».

Итоги урока

В этом уроке Вы узнали: распознавание паттернов связывает признаки задач с семействами алгоритмов: отсортированный массив указывает на бинарный поиск, «все подмножества» — на поиск с возвратом, «минимальная стоимость» — на DP, ограничение n подсказывает допустимую сложность: n ≤ 20 допускает O(2^n), а при n ≤ 10^6 требуется O(n log n) или лучше, а озвучивание паттерна и сложности до написания кода демонстрирует компетентность и позволяет интервьюеру дать обратную связь. Далее Вы примените распознавание паттернов на практике в пробных задачах собеседования с ограничением времени, лёгкой и средней сложности.

Часто задаваемые вопросы

Урок «Шпаргалка по распознаванию шаблонов» бесплатный?

Да — полный текст урока «Шпаргалка по распознаванию шаблонов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс DSA Interview Prep, подпишись на CoddyKit PRO. Курс DSA Interview Prep содержит 4 уроков всего.

Чему я научусь в уроке «Шпаргалка по распознаванию шаблонов»?

Сопоставьте 15 распространённых признаков задач — отсортированный массив, необходимость получить все комбинации, максимизация значения при ограничении и другие — с алгоритмическими шаблонами, которые… Ты практикуешь DSA Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать DSA Interview Prep?

Предыдущий опыт не требуется. DSA Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Шпаргалка по распознаванию шаблонов»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке DSA Interview Prep?

Да. Каждый урок DSA Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Шпаргалка по распознаванию шаблонов
  2. Пробное собеседование с ограничением времени: простые и средние задачи
  3. Обработка крайних случаев и общение на собеседовании
  4. Разбор сложных задач: «Лестница слов II» и «Инопланетный словарь»
← Назад к DSA Interview Prep