Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
Space Complexity: Auxiliary Memory, Recursion Stack and Allocations
Space complexity is how the memory an algorithm keeps alive at once grows with n; recursion depth is memory on the stack too. Recursion failing on a 1.5 MB thread stack, Split vs Span, memoization and reading a 1 GB log file in 52 MB; what ReadAllLines does in a 512 MB container, with real output.
Deriving Time Complexity from Code: Loops, log n and Recursion
To read complexity from code, add sequential blocks, multiply nested loops, call a loop that halves every step log n, and write a recurrence for recursion. With real counts: triangular loops, naive Fibonacci, merge sort, the master theorem, LINQ's hidden loops and an order-matching benchmark going from O(n·m) to O(n+m).
What Is Big-O Notation: Growth Rate, O, Ω, Θ and Worst Case
Big-O describes an algorithm's cost not in seconds but by how its step count grows as the input size n grows. The difference between O, Ω and Θ, choosing n correctly, best/average/worst case, and the real growth of List, HashSet and binary search from 10 to 1,000,000 elements measured with BenchmarkDotNet.
Dynamic Programming 2: Real Problems with Edit Distance, LCS and Knapsack
Two-dimensional DP tables hold prefixes of two strings or a budget: Levenshtein for "did you mean?", LCS for a diff that matches git diff's output, and 0/1 knapsack for budget-limited campaign selection. We write all three in C#, measure a 20x speedup from bounded Levenshtein, show the loop-direction trap in one-row knapsack, and close the series with a pattern decision table.
Dynamic Programming 1: Memoization, Tabulation and Recognizing Subproblems
Dynamic programming turns an exponential computation into polynomial time by solving repeated subproblems once and storing them: naive Fibonacci makes 331 million calls for F(40), memoization 79. We measure memoization, tabulation and O(1)-memory versions in C#, solve climbing stairs, house robber and coin change with a five-step recipe, and show a wrong memo key and a stack overflow with real output.
Greedy Algorithms: When They Work and When They Mislead
A greedy algorithm makes the choice that looks best at each step and is correct only when the greedy choice property holds: picking the meeting that ends first is optimal, picking the largest coin for 6 with {1, 3, 4} coins is not. We write activity selection, a min-heap room counter and Huffman coding in C#, explain the exchange argument, and hunt for counterexamples by comparing greedy with a referee.
Backtracking: Pruning the Search Tree with Permutations, Subsets and Sudoku
Backtracking tries every option systematically with choose, explore and unchoose steps; its real power is pruning branches that cannot reach a solution early: 2,057 nodes instead of 19 million for 8-Queens. In C# we write permutation, subset and combination generators with yield return, N-Queens, a Sudoku solver that starts from the most constrained cell, and a rule-based product configurator.
Union-Find and Minimum Spanning Trees: Building Networks with Kruskal
With path compression and union by rank, Union-Find answers "are these two elements in the same group?" in practically constant time; the naive version is 4,300 times slower on a long chain. We write a DisjointSet in C#, merge duplicate customer accounts through shared e-mails and phones, build the cheapest fiber network between offices with Kruskal, and confirm the result with Prim.
Shortest Paths: Dijkstra, PriorityQueue and a Brief Look at A*
Dijkstra finds the cheapest path in a graph with non-negative weights: with lazy deletion, since PriorityQueue has no decrease-key, in O((V + E) log V). We trace Dijkstra step by step on an intercity shipping network, reconstruct the path, show the wrong result with a negative weight and Bellman-Ford, and measure A* finding the same path on a 200 × 200 warehouse grid with 1,845 cells instead of 33,600.
Topological Sort and Cycle Detection: Dependency Order and Kahn's Algorithm
Topological sort orders the vertices of a DAG so that every dependency comes before its dependents, in O(V + E); Kahn's algorithm uses in-degrees and a queue, DFS uses three colors. We write both in C#, produce seed data and build orders, report the cycle path, and show with real output that EF Core uses the same algorithm in SaveChanges and how the DI container reports a circular dependency.
Graph Basics: Adjacency Lists, BFS and DFS Traversal
Sparse graphs are kept as adjacency lists and BFS finds the fewest steps in O(V + E); on a 5,000-vertex graph BFS over an adjacency matrix is 46 times slower. We write a generic Graph, BFS distances and paths, recursive and iterative DFS, connected components and a grid flood fill in C#, and show with real output that marking visited on dequeue makes 2 million enqueues instead of 2,000.
Tries: Autocomplete, Prefix Search and Memory Cost in C#
A trie stores keys character by character and finds a prefix in O(m) steps, but its memory cost is high: for 234,456 words a sorted array takes 11.7 MB, a trie 148.9 MB. We write a trie with top-N suggestions in C#, solve the Turkish İ/ı case folding trap, build a minimal API and an Angular search box, and compare a sorted array, PostgreSQL LIKE and the trie with measurements.