Skip to main content

dsa-interview-patterns

Classic coding interview patterns including two pointers, sliding window, binary search variants, fast/slow pointers, prefix sums, interval merging, and monotonic stack. Use when: solving array or string problems under interview constraints, recognising which pattern fits a given input shape, implementing cursor-based pagination, analysing date-range or sorted time-series queries, reviewing LINQ chains for hidden complexity, or teaching pattern-first problem solving.

Datos de origen

Repositorio
willvelida/biotrackr
Última actividad en el origen
18 de abril de 2026 a las 23:31
Idioma detectado de SKILL.md
inglés
Estrellas
6
Forks
3

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
dsa-interview-patterns
description
Classic coding interview patterns including two pointers, sliding window, binary search variants, fast/slow pointers, prefix sums, interval merging, and monotonic stack. Use when: solving array or string problems under interview constraints, recognising which pattern fits a given input shape, implementing cursor-based pagination, analysing date-range or sorted time-series queries, reviewing LINQ chains for hidden complexity, or teaching pattern-first problem solving.
# DSA Interview Patterns ## When to Use - Approaching a new problem and needing to identify which pattern applies - Implementing or reviewing two-pointer, sliding window, or binary search logic - Teaching pattern-first problem solving (recognise the shape, apply the template) - Reviewing pagination cursor logic or date-range query strategies - Analysing activity log aggregation for hidden O(n²) in prefix sum candidates - Preparing for technical interviews with common pattern recognition ## Two Pointers Two pointers move through a collection — usually from both ends toward the middle, or both from the start at different speeds. ### Same-Direction (Fast / Slow) ```csharp // Remove duplicates from sorted array in-place (O(n) time, O(1) space) int slow = 0; for (int fast = 1; fast < nums.Length; fast++) { if (nums[fast] != nums[slow]) nums[++slow] = nums[fast]; } return slow + 1; ``` ### Opposite-Direction (Converging) ```csharp // Two-sum on sorted array (O(n) time) int left = 0, right = nums.Length - 1; while (left < right) { int sum = nums[left] + nums[right]; if (sum == target) return (left, right); if (sum < target) left++; else right--; } ``` ### When to Use Two Pointers - Input is sorted or can be sorted - Looking for a pair / triplet satisfying a condition - Removing elements in-place - Comparing characters from both ends of a string (palindrome check) ## Sliding Window A window is a contiguous sub-sequence. Sliding window avoids the O(n²) of checking all pairs/windows by maintaining and updating a running state as the window slides. ### Fixed-Size Window ```csharp // Maximum sum of any subarray of length k — O(n) int windowSum = 0; for (int i = 0; i < k; i++) { windowSum += nums[i]; } int maxSum = windowSum; for (int i = k; i < nums.Length; i++) { windowSum += nums[i] - nums[i - k]; maxSum = Math.Max(maxSum, windowSum); } ``` ### Variable-Size Window ```csharp // Longest substring with at most k distinct characters — O(n) int left = 0, maxLen = 0; var freq = new Dictionary<char, int>(); for (int right = 0; right < s.Length; right++) { freq[s[right]] = freq.GetValueOrDefault(s[right]) + 1; while (freq.Count > k) { freq[s[left]]--; if (freq[s[left]] == 0) freq.Remove(s[left]); left++; } maxLen = Math.Max(maxLen, right - left + 1); } ``` ### Biotrackr Anchor — Pagination as Sliding Window `PaginationResponse<T>` in Biotrackr APIs is a fixed-size sliding window over a sorted dataset. Cosmos DB continuation tokens are variable-size window cursors — the boundary is a bookmark, not a numeric offset: ``` Fixed: pageNumber=3, pageSize=20 → offset = 40, length = 20 Cursor: continuationToken="{etag}" → start after last seen item ``` **Teaching angle:** Cursor-based pagination avoids "page drift" when items are inserted mid-pagination. It is the variable-size window pattern: the window start is pinned to the last seen item, not a fixed numeric offset. ## Binary Search Binary search works on any **monotone function** — not just sorted arrays. The key is: "does the condition hold for all values on one side?" ### Template ```csharp // Generalised binary search — finds leftmost position where condition is true int left = 0, right = boundary; while (left < right) { int mid = left + (right - left) / 2; if (Condition(mid)) right = mid; // condition true → search left half else left = mid + 1; // condition false → search right half } return left; // leftmost true position ``` ### Biotrackr Anchor — Date-Range Queries on Sorted Time-Series Activity, sleep, and vitals data in Biotrackr are stored sorted by `date`. A range query `/range/{startDate}/{endDate}` on sorted records is binary search applied twice: ``` find first index where date >= startDate → binary search left boundary find last index where date <= endDate → binary search right boundary ``` **Teaching angle:** Cosmos DB range queries on indexed `date` fields use a B-tree for O(log n) boundary location — the same concept as binary search, implemented in a tree. ## Fast/Slow Pointers Fast pointer moves at 2× the speed of slow. Useful for cycle detection and finding the middle of a linked list. ``` Floyd's cycle detection: slow moves 1 step at a time fast moves 2 steps at a time If they meet: cycle exists If fast reaches null: no cycle ``` ### When to Use Fast/Slow - Detect cycle in a linked list (Floyd's algorithm) - Find the middle node of a linked list - Detect duplicate in an array treated as implicit linked list (Floyd's on values) ## Prefix Sum A prefix sum array P where `P[i] = nums[0] + ... + nums[i]` allows O(1) range sum queries: ```csharp // Build prefix sum — O(n) int[] prefix = new int[nums.Length + 1]; for (int i = 0; i < nums.Length; i++) prefix[i + 1] = prefix[i] + nums[i]; // Query sum of [left, right] — O(1) int rangeSum = prefix[right + 1] - prefix[left]; ``` ### Biotrackr Anchor — Activity Log Aggregation `Biotrackr.Activity.Api` returns activity records by date. Aggregating total steps over a date range without prefix sums requires summing each record in the range: O(k) where k is the range size. With a pre-built prefix sum over sorted daily totals, any range aggregate is O(1) after O(n) preprocessing. **Teaching angle:** Build the prefix sum once; answer all range queries in O(1). The trade-off is O(n) space. When you have many range queries on static data, prefix sums are the right tool. ## Pattern Recognition Guide Use the input shape to identify the right pattern: | Input Shape | Common Patterns | |---|---| | Sorted array, find target | Binary search | | Sorted array, find pair satisfying condition | Two pointers (converging) | | Array, longest/smallest subarray satisfying condition | Sliding window | | Linked list, detect cycle or find middle | Fast/slow pointers | | Array, range sum queries | Prefix sum | | Array of intervals, merge or insert | Sort by start, linear sweep | | Matrix, find path or connected region | BFS or DFS | | String, all permutations/combinations | Backtracking | | Scheduling with priorities | Heap / priority queue | | "Nearest greater element" | Monotonic stack | ## Monotonic Stack A monotonic stack maintains elements in a consistently increasing or decreasing order. Useful for "next greater/smaller element" problems in O(n). ```csharp // Next greater element for each item — O(n) var result = new int[nums.Length]; var stack = new Stack<int>(); // stores indices for (int i = 0; i < nums.Length; i++) { while (stack.Count > 0 && nums[stack.Peek()] < nums[i]) result[stack.Pop()] = nums[i]; stack.Push(i); } // Remaining indices have no greater element → result stays 0 ``` **When to reach for monotonic stack:** "For each element, find the first element to its left/right that is larger/smaller." This pattern appears in histogram problems, stock span, and trapping rainwater.
Ver en GitHub