Ściągawka rozpoznawania wzorców
Mapować 15 typowych sygnałów problemu (posortowana tablica, potrzeba znalezienia wszystkich kombinacji, maksymalizacja wartości przy ograniczeniu itd.) na wzorce algorytmiczne, które rozwiązują je najszybciej
Ściągawka rozpoznawania wzorców to bezpłatna lekcja DSA Interview Prep na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej DSA Interview Prep, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs DSA Interview Prep zawiera 4 lekcji w sumie.
Gra w rozpoznawanie wzorców w 60 sekund
Podczas prawdziwej rozmowy rekrutacyjnej mają Państwo około 60 sekund po przeczytaniu zadania, aby określić, który wzorzec algorytmiczny należy zastosować, zanim osoba rekrutująca oczekiwać będzie rozpoczęcia pisania kodu. Jest to najważniejsza umiejętność do rozwijania — nie zapamiętywanie implementacji, lecz rozpoznawanie, po jakie narzędzie należy sięgnąć.
Rozpoznawanie wzorców wynika z mapowania sygnałów problemu (słów i ograniczeń zawartych w treści zadania) na znane rodziny algorytmów. Po rozpoznaniu wzorca implementacja staje się ćwiczeniem polegającym na wypełnieniu szablonu. Ta lekcja to usystematyzowana ściągawka obejmująca 15 najczęstszych sygnałów problemu i odpowiadające im wzorce.
# 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)Sygnały 1–3: wzorce dla tablic i ciągów
Najczęstsze sygnały w zadaniach dotyczących tablic i ciągów:
- Posortowana tablica + znalezienie celu → Wyszukiwanie binarne O(log n)
- Znalezienie pary/trójki sumującej się do celu → Dwa wskaźniki O(n), jeśli tablica jest posortowana, mapa haszująca O(n), jeśli nie jest posortowana
- Najdłuższa/najkrótsza podtablica lub podciąg spełniające warunek → Okno przesuwne O(n)
- Maksymalna/minimalna suma spójnej podtablicy → Algorytm Kadane'a O(n)
- Wykrywanie duplikatów → Zbiór haszujący O(n) lub sortowanie O(n log n)
Jeśli tablica jest posortowana, zawsze najpierw rozważcie Państwo wyszukiwanie binarne. Nieposortowana tablica + suma docelowa + O(n) = prawie zawsze mapa haszująca do wyszukiwania dopełnienia.
# 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}')Sygnały 4–6: wzorce dla drzew i grafów
Sygnały w zadaniach dotyczących drzew i grafów oraz odpowiadające im wzorce:
- Przechodzenie poziom po poziomie / najkrótsza ścieżka w grafie nieważonym → BFS z kolejką dwustronną O(V+E)
- Przeszukanie wszystkich ścieżek / wykrywanie cyklu / kolejność DFS → Rekurencyjny lub iteracyjny DFS O(V+E)
- BST + właściwości przejścia in-order (k-ty element, posortowana kolejność) → DFS in-order O(n)
- Najniższy wspólny przodek → Rekurencyjne przechodzenie z zapisywaniem ścieżki O(n)
- Spójne składowe / połączenie dwóch grup → 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}')Sygnały 7–9: sygnały wskazujące na programowanie dynamiczne
Sygnały wskazujące na programowanie dynamiczne są najtrudniejsze do rozpoznania. Należy zwrócić uwagę na następujące słowa kluczowe:
- „Liczba sposobów na...” → Programowanie dynamiczne zliczające (dodawanie liczby sposobów dla podproblemów)
- „Minimalny/maksymalny koszt osiągnięcia...” → Programowanie dynamiczne optymalizacyjne (wybieranie minimum/maksimum z podproblemów)
- „Czy możemy osiągnąć...” (wykonalność) → Programowanie dynamiczne boolowskie (OR podproblemów)
- Podproblem określony przez dwa indeksy w ciągu → Programowanie dynamiczne 2D (LCS, odległość edycyjna)
- Wybór lub pominięcie elementów przy ograniczeniu pojemności → Programowanie dynamiczne dla problemu plecakowego
- Optymalna podstruktura + nakładające się podproblemy → Sprawdzenie drzewa rekurencji pod kątem powtarzających się wywołań → programowanie dynamiczne
# 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}')Sygnały 10–12: sygnały wskazujące na kopiec, stos i algorytm zachłanny
Sygnały w zadaniach wykorzystujących kopiec, stos monotoniczny i algorytmy zachłanne:
- Elementy Top-K / k-ty największy lub najmniejszy element → Kopiec (kopiec minimalny dla K największych elementów, kopiec maksymalny dla k-tego najmniejszego elementu) O(n log k)
- Mediana strumieniowa → Dwa kopce (kopiec maksymalny dla mniejszej połowy + kopiec minimalny dla większej połowy)
- Następny większy/mniejszy element → Stos monotoniczny O(n)
- Prostokąt o największym polu / zbieranie wody → Stos monotoniczny O(n)
- Planowanie przedziałów / maksymalizacja liczby rozłącznych przedziałów → Algorytm zachłanny (sortowanie według czasu zakończenia)
# 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}')Sygnały 13–15: nawroty i operacje bitowe
Sygnały wskazujące na zastosowanie nawrotów i operacji bitowych:
- Generowanie wszystkich podzbiorów / permutacji / kombinacji → Backtracking O(2^n lub n!)
- Spełnianie ograniczeń (hetmany, Sudoku) → Backtracking z przycinaniem
- Znalezienie jednego brakującego lub unikatowego elementu → XOR O(n), pamięć O(1)
- Wyliczanie wszystkich podzbiorów małego zbioru (n ≤ 20) → Wyliczanie masek bitowych 2^n
- Zliczanie ustawionych bitów / sprawdzanie, czy liczba jest potęgą dwójki → Sztuczki bitowe (n & (n-1))
- Programowanie dynamiczne z kompresją stanu dla małego zbioru → Programowanie dynamiczne z maską bitową 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}')Analiza ograniczeń: co mówi Państwu N
Ograniczenie rozmiaru danych wejściowych n bezpośrednio wskazuje akceptowalną złożoność czasową, a tym samym rodzinę algorytmów:
- n ≤ 20: O(2^n) lub O(n!) jest akceptowalne — programowanie dynamiczne z maską bitową, backtracking
- n ≤ 500: O(n³) jest akceptowalne — algorytm Floyda-Warshalla, programowanie dynamiczne metodą brute force
- n ≤ 5000: O(n²) jest akceptowalne — naiwne programowanie dynamiczne, sortowanie kwadratowe
- n ≤ 10^6: potrzebne jest O(n log n) — sortowanie przez scalanie, kopiec, wyszukiwanie binarne
- n ≤ 10^8: potrzebne jest O(n) — dwa wskaźniki, okno przesuwne, liniowe programowanie dynamiczne
Analiza ograniczeń powinna być pierwszym krokiem po przeczytaniu zadania — przed wyborem dowolnego algorytmu.
# 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}')Zadanie → wzorzec: szybkie ćwiczenia
Ćwiczcie Państwo to mapowanie, aż stanie się automatyczne. Przeczytajcie każdy opis zadania i określcie wzorzec przed zapoznaniem się z rozwiązaniem. Liczy się szybkość — podczas rozmowy rekrutacyjnej powinni Państwo rozpoznać wzorzec w mniej niż 60 sekund:
- „Mając posortowaną tablicę, sprawdź, czy dowolne dwa elementy sumują się do K”
- „Mając drzewo, znajdź jego średnicę (najdłuższą ścieżkę między dowolnymi dwoma węzłami)”
- „Mając n zadań z okresem karencji k, znajdź minimalną liczbę przedziałów czasowych CPU”
- „Mając ciąg, znajdź najdłuższy palindromiczny podciąg”
- „Mając liczby od 1 do n, z których jednej brakuje, znajdź brakującą liczbę”
# 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')Czerwone flagi: kiedy wzorzec zawodzi
Nawet doświadczeni inżynierowie początkowo wybierają niewłaściwy wzorzec. Rozpoznajcie Państwo następujące sygnały świadczące o tym, że obecne podejście jest błędne, i zmieńcie je:
- Rozwiązanie O(n²) przechodzi małe testy, ale dla dużych danych kończy się TLE → potrzebują Państwo mapy haszującej, wyszukiwania binarnego lub struktury monotonicznej
- Algorytm zachłanny nie przechodzi kontrprzykładu → należy spróbować programowania dynamicznego
- Przestrzeń stanów programowania dynamicznego jest zbyt duża → należy poszukać dowodu poprawności algorytmu zachłannego lub lepszej definicji stanu
- BFS zwraca niepoprawną odpowiedź → należy sprawdzić, czy zamiast BFS (dla grafu nieważonego) potrzebny jest algorytm Dijkstry (dla grafu ważonego)
- Występują wyjątki null pointer → przed implementacją należy dodać przypadki bazowe i zabezpieczenia dla przypadków brzegowych
# 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}')Komunikowanie rozpoznania wzorca podczas rozmów rekrutacyjnych
Podczas rozmów rekrutacyjnych głośne wyjaśnianie sposobu rozpoznania wzorca świadczy o Państwa wiedzy i daje osobie rekrutującej możliwość pokierowania Państwem, jeśli obiorą Państwo niewłaściwy kierunek. Należy użyć następującej struktury wypowiedzi:
- „Widzę, że tablica jest posortowana, więc rozważam wyszukiwanie binarne...”
- „Zadanie wymaga znalezienia maksymalnej podtablicy, co jest klasycznym problemem dla algorytmu Kadane'a...”
- „Potrzebujemy wszystkich możliwych podzbiorów, co sugeruje backtracking z drzewem rekurencji...”
- „Ograniczenie n ≤ 20 oznacza, że 2^n = 1M jest akceptowalne, więc można zastosować programowanie dynamiczne z maską bitową...”
Po określeniu wzorca należy wspomnieć o złożoności czasowej i pamięciowej, zanim zostanie napisana choćby jedna linia kodu. Pokazuje to, że myślą Państwo o wydajności jeszcze przed implementacją.
# 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']
)Budowanie słownictwa związanego z rozpoznawaniem wzorców
Najszybszym sposobem na rozwijanie umiejętności rozpoznawania wzorców jest rozwiązywanie zadań w tematycznych seriach, a nie losowo. Proszę poświęcić jeden tydzień wyłącznie na zadania z oknem przesuwnym. Następnie tydzień na zadania z dwoma wskaźnikami, a potem na zadania z programowania dynamicznego. Szybkie rozwiązanie 20 zadań tego samego typu pozwala rozwinąć intuicję potrzebną do rozpoznawania danego wzorca na pierwszy rzut oka.
Po każdym zadaniu proszę zapisać jednozdaniową „notatkę o wzorcu”: sygnał problemu i wzorzec, który on wywołał. Proszę zbudować własną ściągawkę. Po rozwiązaniu 200 zadań w tematycznych seriach będą Państwo rozpoznawać około 90% zadań rekrutacyjnych w mniej niż 30 sekund — pozostałe 10% wymaga uważnej analizy nawet od doświadczonych inżynierów.
# 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"]}')Szybki test
Sprawdźcie Państwo swoją wiedzę na temat zagadnień Data Structures & Algorithms — Coding Interview Prep z tej lekcji.
Podsumowanie lekcji
W tej lekcji nauczyli się Państwo, że: rozpoznawanie wzorców mapuje sygnały problemu na rodziny algorytmów — posortowana tablica wskazuje na wyszukiwanie binarne, „wszystkie podzbiory” wskazują na backtracking, a „minimalny koszt” wskazuje na programowanie dynamiczne, ograniczenie n wskazuje akceptowalną złożoność: n ≤ 20 pozwala na O(2^n), natomiast n ≤ 10^6 wymaga O(n log n) lub lepszego rozwiązania, a także że wyjaśnienie wzorca i złożoności przed rozpoczęciem kodowania świadczy o wiedzy i umożliwia osobie rekrutującej przekazanie informacji zwrotnej. Następnie przećwiczymy rozpoznawanie wzorców na czas podczas próbnych zadań rekrutacyjnych o łatwym i średnim poziomie trudności.
Często zadawane pytania
Czy lekcja „Ściągawka rozpoznawania wzorców” jest bezpłatna?
Tak — pełny tekst „Ściągawka rozpoznawania wzorców” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu DSA Interview Prep, przejdź na CoddyKit PRO. Kurs DSA Interview Prep zawiera 4 lekcji w sumie.
Co nauczysz się w „Ściągawka rozpoznawania wzorców”?
Mapować 15 typowych sygnałów problemu (posortowana tablica, potrzeba znalezienia wszystkich kombinacji, maksymalizacja wartości przy ograniczeniu itd.) na wzorce algorytmiczne, które rozwiązują je na… Ćwiczysz DSA Interview Prep z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć DSA Interview Prep?
Nie wymagamy żadnego doświadczenia. DSA Interview Prep w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.
Ile czasu zajmuje lekcja „Ściągawka rozpoznawania wzorców”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji DSA Interview Prep?
Tak. Każda lekcja DSA Interview Prep zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Ściągawka rozpoznawania wzorców
- Próbna rozmowa techniczna na czas: problemy łatwe i średnie
- Przypadki brzegowe i komunikacja podczas rozmowy technicznej
- Omówienie trudnych problemów: Word Ladder II i Alien Dictionary