DSA Notes
HubAlgorithm vs Data Structure — Key Differences, Definitions, and How They Work TogetherApplications of DSA — How Data Structures and Algorithms Power Real-World SoftwareTime and Space Complexity — A Complete BeginnerWhat is DSA? — A Complete BeginnerWhy Learn DSA? — Career Benefits, Real-World Impact, and Long-Term ValueAsymptotic Analysis — Complete Framework with Recurrence Relations and Master TheoremBest, Average, and Worst Case Analysis — A Practical Guide for Every AlgorithmBig O Notation — Complete Guide with Formal Definition, Rules, and ExamplesBig Omega Notation — Lower Bounds, Best Case, and Formal DefinitionBig Theta (Θ) Notation — Tight Bounds and Exact Growth RatesSpace Complexity — Memory Analysis, Auxiliary Space, and Time-Space TradeoffsTime Complexity Examples — 25 Worked Problems from Basic to AdvancedArray Interview Problems — 15 Classic Problems with Complete SolutionsArray Operations — Every Operation Explained with Code, Complexity, and Edge CasesArray Rotation — Algorithms, Techniques, and Interview ProblemsArray Searching — Linear Search, Binary Search, and Advanced TechniquesArrays — The Complete Introduction to the Most Fundamental Data StructureDynamic Arrays — How Python Lists and ArrayLists Work InternallyMultidimensional Arrays — 2D Arrays, Matrices, and Memory LayoutSliding Window Technique — Complete Guide with 10 Classic ProblemsAnagram Problems — Detection, Grouping, and Sliding Window VariationsPalindrome Problems — Check, Longest, Count, and Expand Around CenterPattern Searching — KMP, Rabin-Karp, and Boyer-Moore AlgorithmsString Interview Problems — 10 Classic Problems with Complete SolutionsString Matching — Longest Common Subsequence, Edit Distance, and Z-AlgorithmString Operations — Complete Reference with Complexity and ImplementationStrings — Complete Introduction to String Data Structure and OperationsCircular Linked List — Structure, Operations, and ApplicationsDoubly Linked List — Complete Implementation with Bidirectional OperationsLinked List Interview Problems — 12 Classic Problems with Complete SolutionsLinked Lists — A Complete Introduction with Memory Model and TypesLinked List Operations — Every Technique with Code and ComplexityReverse Linked List — All Approaches from Basic to AdvancedSingly Linked List — Complete Implementation with All OperationsBalanced Parentheses — Stack-Based Validation with All VariantsInfix, Prefix, and Postfix Expressions — Stack-Based Conversion and EvaluationStack Implementation — Three Complete Implementations with Edge CasesStack Interview Problems — 10 Classic Problems with Complete SolutionsStack — Complete Introduction to LIFO Data StructureStack Using Arrays — Memory Layout, Capacity Management, and PerformanceStack Using Linked List — Implementation, Analysis, and When to Use ItCircular Queue — The Ring Buffer Explained with ImplementationDeque — Double-Ended Queue with Complete Implementation and ApplicationsPriority Queue — Complete Guide from Concept to ImplementationQueue Applications — BFS, Level-Order Traversal, 01-BFS, and MoreQueue Implementation — Array, Linked List, and Two-Stack ApproachesQueue Interview Problems — 10 Classic Problems with Complete SolutionsQueue — Complete Introduction to the FIFO Data StructureAVL Tree - Self-Balancing Binary Search TreeBinary Search Tree (BST)Binary Tree - Structure and OperationsFenwick Tree (Binary Indexed Tree)Red-Black Tree - Another Balanced BSTSegment Tree - Range Query Data StructureTree Interview Problems CollectionTree Data Structure FundamentalsTree Traversals - Inorder, Preorder, Postorder, Level OrderHeap — Complete Introduction to the Priority-Based Tree Data StructureHeap Operations — Complete Reference with Complexity AnalysisHeap Problems — 8 Classic Interview Problems with Complete SolutionsMax Heap — Complete Implementation and ApplicationsMin Heap — Complete Implementation with All OperationsPriority Queue Using Heap — Implementation, Applications, and PatternsBellman-Ford Algorithm — Shortest Path with Negative Weights and Cycle DetectionBFS Algorithm — Breadth-First Search with All Applications and VariantsDFS Algorithm — Depth-First Search with Cycle Detection and All ApplicationsDijkstraFloyd-Warshall Algorithm — All-Pairs Shortest Paths with Complete AnalysisGraph Interview Problems — 12 Classic Problems with Complete SolutionsGraph — Complete Introduction to the Most Powerful Data StructureGraph Representation — Adjacency List, Matrix, Edge List with Complete AnalysisKruskalMinimum Spanning Tree — Definition, Properties, and ApplicationsPrimShortest Path Algorithms — Complete Comparison and Selection GuideTopological Sorting — DFS and BFS (KahnUnion-Find (DSU) in Graphs — Connected Components and Dynamic ConnectivitySeparate Chaining — Complete Implementation and AnalysisCollision Handling — Chaining vs Open Addressing Complete ComparisonHash Functions — Design, Properties, and Common ImplementationsHashing — Complete Introduction to Hash Tables and Hash FunctionsHashing Problems — 10 Classic Interview Problems with Complete SolutionsOpen Addressing — Linear Probing, Quadratic Probing, and Double HashingBubble Sort — Complete Analysis with Optimizations and When to Use ItCounting Sort — O(n+k) Sorting That Breaks the Comparison Lower BoundHeap Sort — Guaranteed O(n log n) with O(1) SpaceInsertion Sort — The O(n) Best Case Sort That Powers PythonMerge Sort — Complete Guide to the Guaranteed O(n log n) Stable SortQuick Sort — The Fastest Practical Sorting Algorithm with Complete AnalysisRadix Sort — O(nk) Digit-by-Digit Sorting for Large Integer RangesSelection Sort — Complete Analysis with Swaps Minimization PropertySorting Algorithm Comparison — The Complete Decision GuideSorting — Complete Introduction to Sorting AlgorithmsBinary Search — Complete Guide with All Variants and Proof of CorrectnessInterpolation Search — O(log log n) Search for Uniformly Distributed DataLinear Search — Complete Guide with All Variants and ApplicationsSearch Algorithm Comparison — Choosing the Right Search for Every SituationSearching Interview Problems — 10 Classic Problems with Complete SolutionsTernary Search — Finding Maximum/Minimum of Unimodal FunctionsBacktracking Introduction — The Recursive Exploration with UndoRecursion Basics — The Complete BeginnerRecursion Problems — 12 Classic Problems from Basic to AdvancedRecursion Tree — Visualizing Recursion for Complexity AnalysisRecursion vs Iteration — When to Use Each and How to ConvertTail Recursion — Definition, Optimization, and Converting to IterationDP Interview Problems — 12 Classic Problems with Pattern Recognition GuideDynamic Programming — Complete Introduction with Properties and Problem IdentificationFibonacci DP — From Exponential to Linear with Memoization and Matrix ExponentiationKnapsack Problem — 0/1, Unbounded, and Fractional with Complete AnalysisLongest Common Subsequence — Complete Guide with DP Table and String VariantsLongest Increasing Subsequence — O(n log n) with Patience SortingMatrix Chain Multiplication — Interval DP with Complete AnalysisMemoization — Top-Down Dynamic Programming with CachingTabulation — Bottom-Up Dynamic Programming with Complete Table BuildingActivity Selection Problem — Greedy Scheduling with Proof of CorrectnessFractional Knapsack — Greedy by Value Density with ProofGreedy Interview Problems — 10 Classic Problems with Complete SolutionsGreedy Algorithms — Complete Introduction with Proof TechniquesHuffman Coding — Optimal Prefix-Free Data CompressionJob Sequencing Problem — Greedy Scheduling with DeadlinesBacktracking — The Complete Guide to Recursive Exploration with UndoBacktracking Problems — 12 Classic Interview Problems with Complete SolutionsN-Queens Problem — Complete Solution with Backtracking and OptimizationRat in a Maze — Backtracking Path Finding with All SolutionsSubset Generation — All Subsets, Combinations, and Partitions with BacktrackingSudoku Solver — Backtracking with Constraint PropagationCodeforces Guide — Complete Strategy to Reach 1800+ RatingCommon CP Techniques — Essential Algorithms Every Competitive Programmer Must KnowContest Strategies — How to Perform Your Best in Competitive Programming ContestsCompetitive Programming — Complete Introduction for BeginnersFast Input/Output — Why I/O Speed Matters and Complete Templates for C++ and PythonLeetCode Guide — Complete Strategy to Crack FAANG InterviewsBit Manipulation — Complete Guide with All Tricks and Interview ProblemsBloom Filter — Space-Efficient Probabilistic Membership TestingComputational Geometry — Points, Lines, Convex Hull, and Geometric AlgorithmsDisjoint Set Union (DSU) — Union-Find with Path Compression and Union by RankRandomized Algorithms — Las Vegas, Monte Carlo, and Probabilistic TechniquesSkip List — The Probabilistic Data Structure that Competes with Balanced BSTsSuffix Array — Construction, LCP Array, and String Search ApplicationsTrie Data Structure — Complete Guide with Implementation and ApplicationsAutocomplete System Using TrieLibrary Management System Using DSARoute Finder Using GraphsMini Search Engine ProjectSocial Network Analysis Using GraphsEssential Coding Patterns for InterviewsDSA Cheatsheet: Quick ReferenceEssential DSA Interview QuestionsFAANG DSA Sheet: Company-Specific Patterns and ProblemsProblem Solving Strategies for Coding InterviewsComplexity CheatsheetImportant Algorithms SummaryBest Practice Platforms for DSARecommended Books for DSA
Solve 12 classic DP interview problems — maximum product subarray, decode ways, jump game II, unique paths with obstacles, minimum path sum, coin change II, target sum, longest palindromic substring, word break, stock problems, regular expression matching, and wildcard matching.
Problem 1 — Maximum Product Subarray
Example
def max_product(nums):
"""
Find contiguous subarray with maximum product.
Track both max and min (negative × negative = positive!)
Time: O(n), Space: O(1)
"""
max_prod = min_prod = result = nums[0]
for num in nums[1:]:
candidates = (num, max_prod * num, min_prod * num)
max_prod = max(candidates)
min_prod = min(candidates)
result = max(result, max_prod)
return result
print(max_product([2, 3, -2, 4])) # 6 ([2,3])
print(max_product([-2, 0, -1])) # 0
print(max_product([-2, 3, -4])) # 24 ([-2,3,-4])
Problem 3 — Jump Game II (Minimum Jumps)
Example
def jump_game_2(nums):
"""
Minimum jumps to reach last index.
Greedy DP: at each step, go as far as possible.
Time: O(n), Space: O(1)
"""
jumps = 0
current_end = 0 # Farthest position reachable with current jumps
farthest = 0 # Farthest position reachable overall
for i in range(len(nums) - 1):
farthest = max(farthest, i + nums[i])
if i == current_end: # We MUST jump here
jumps += 1
current_end = farthest
return jumps
print(jump_game_2([2,3,1,1,4])) # 2
print(jump_game_2([2,3,0,1,4])) # 2
Problem 4 — Unique Paths with Obstacles
Example
def unique_paths_obstacles(grid):
"""
Count paths in grid with obstacles (1=blocked).
Only move right or down.
"""
m, n = len(grid), len(grid[0])
if grid[0][0] == 1 or grid[m-1][n-1] == 1: return 0
dp = [[0]*n for _ in range(m)]
dp[0][0] = 1
for i in range(m):
for j in range(n):
if i == 0 and j == 0: continue
if grid[i][j] == 1: continue # Obstacle
above = dp[i-1][j] if i > 0 else 0
left = dp[i][j-1] if j > 0 else 0
dp[i][j] = above + left
return dp[m-1][n-1]
grid = [[0,0,0],[0,1,0],[0,0,0]]
print(unique_paths_obstacles(grid)) # 2
Problem 5 — Coin Change II (Count Ways)
Example
def change(amount, coins):
"""
Count number of ways to make amount using coins.
Each coin can be used unlimited times.
Unbounded knapsack variant.
"""
dp = [0] * (amount + 1)
dp[0] = 1 # One way to make 0: use no coins
for coin in coins:
for a in range(coin, amount+1): # Forward = unbounded
dp[a] += dp[a - coin]
return dp[amount]
print(change(5, [1,2,5])) # 4 ways
print(change(3, [2])) # 0 (impossible)
print(change(10, [10])) # 1
Problem 6 — Target Sum
Example
def find_target_sum_ways(nums, target):
"""
Assign + or - to each number. Count ways to reach target.
DP: dp[sum] = number of ways to reach this sum.
"""
from collections import defaultdict
dp = defaultdict(int)
dp[0] = 1
for num in nums:
next_dp = defaultdict(int)
for curr_sum, count in dp.items():
next_dp[curr_sum + num] += count
next_dp[curr_sum - num] += count
dp = next_dp
return dp[target]
print(find_target_sum_ways([1,1,1,1,1], 3)) # 5
print(find_target_sum_ways([1], 1)) # 1
Problem 7 — Longest Palindromic Substring
Example
def longest_palindrome(s):
"""
Find longest palindromic substring.
Expand around center: O(n²) time, O(1) space.
"""
start = end = 0
def expand(l, r):
while l >= 0 and r < len(s) and s[l] == s[r]:
l -= 1; r += 1
return l+1, r-1
for i in range(len(s)):
l1, r1 = expand(i, i) # Odd length
l2, r2 = expand(i, i+1) # Even length
if r1-l1 > end-start: start, end = l1, r1
if r2-l2 > end-start: start, end = l2, r2
return s[start:end+1]
print(longest_palindrome("babad")) # "bab" or "aba"
print(longest_palindrome("cbbd")) # "bb"
Problem 8 — Stock Buy and Sell with Cooldown
Example
def max_profit_cooldown(prices):
"""
After selling, must wait 1 day (cooldown).
States: held (holding stock), sold (just sold), rest (cooling down or idle)
"""
held = float('-inf')
sold = 0
rest = 0
for price in prices:
prev_held, prev_sold, prev_rest = held, sold, rest
held = max(prev_held, prev_rest - price) # Keep or buy
sold = prev_held + price # Sell from held
rest = max(prev_rest, prev_sold) # Cool down or stay
return max(sold, rest)
print(max_profit_cooldown([1,2,3,0,2])) # 3 ([1→3] sell, cooldown, [0→2] buy→sell)
print(max_profit_cooldown([1])) # 0
Problem 9 — Stock with Transaction Fee
Example
def max_profit_fee(prices, fee):
"""
Any number of transactions but each has a fee.
held: max profit while holding stock
cash: max profit without holding stock
"""
cash = 0
held = -prices[0]
for price in prices[1:]:
cash = max(cash, held + price - fee) # Sell
held = max(held, cash - price) # Buy
return cash
print(max_profit_fee([1,3,2,8,4,9], 2)) # 8
Problem 10 — Regular Expression Matching
Example
def is_match_regex(s, p):
"""
'.' matches any single character.
'*' matches zero or more of the preceding element.
"""
m, n = len(s), len(p)
dp = [[False]*(n+1) for _ in range(m+1)]
dp[0][0] = True
# Initialize: pattern like a*, a*b*, a*b*c* can match empty string
for j in range(2, n+1):
if p[j-1] == '*':
dp[0][j] = dp[0][j-2]
for i in range(1, m+1):
for j in range(1, n+1):
if p[j-1] == '*':
# Use zero occurrences of preceding element
dp[i][j] = dp[i][j-2]
# Use one or more occurrences
if p[j-2] == '.' or p[j-2] == s[i-1]:
dp[i][j] = dp[i][j] or dp[i-1][j]
elif p[j-1] == '.' or p[j-1] == s[i-1]:
dp[i][j] = dp[i-1][j-1]
return dp[m][n]
print(is_match_regex("aa", "a")) # False
print(is_match_regex("aa", "a*")) # True
print(is_match_regex("ab", ".*")) # True
Problem 11 — Largest Rectangle in Histogram (DP + Stack)
Example
def largest_rectangle(heights):
"""
Max rectangle area in histogram.
Monotonic stack: O(n) time.
"""
stack = []
max_area = 0
heights = heights + [0] # Sentinel to flush remaining bars
for i, h in enumerate(heights):
while stack and heights[stack[-1]] > h:
height = heights[stack.pop()]
width = i if not stack else i - stack[-1] - 1
max_area = max(max_area, height * width)
stack.append(i)
return max_area
print(largest_rectangle([2,1,5,6,2,3])) # 10
print(largest_rectangle([2,4])) # 4
Problem 12 — Count Distinct Subsequences
Example
def num_distinct(s, t):
"""
Count distinct subsequences of s that equal t.
dp[i][j] = ways to form t[:j] from s[:i]
"""
m, n = len(s), len(t)
dp = [[0]*(n+1) for _ in range(m+1)]
for i in range(m+1): dp[i][0] = 1 # Empty t: one way (use nothing)
for i in range(1, m+1):
for j in range(1, n+1):
dp[i][j] = dp[i-1][j] # Don't use s[i-1]
if s[i-1] == t[j-1]:
dp[i][j] += dp[i-1][j-1] # Use s[i-1]
return dp[m][n]
print(num_distinct("rabbbit", "rabbit")) # 3
print(num_distinct("babgbag", "bag")) # 5
DP Pattern Recognition Guide
| Pattern in problem | DP Type | State definition |
|---|---|---|
| "Minimum steps/coins/edits" | 1D DP | dp[remaining] |
| "Count ways" | 1D/2D DP | dp[amount] or dp[i][j] |
| "Grid, only right/down" | 2D DP | dp[row][col] |
| "Two strings, compare" | 2D string DP | dp[i][j] for s1[:i],s2[:j] |
| "Subsequence/substring" | LCS/LIS variants | dp[i][j] or dp[i] |
| "Range [i..j]" | Interval DP | dp[i][j] |
| "Subsets" | Knapsack variants | dp[mask] or dp[sum] |
| "Stock trading" | State machine DP | held/sold/rest states |
*Dynamic Programming section complete.*
Continue the lesson path
Study next in this module
01Dynamic ProgrammingDynamic Programming — Complete Introduction with Properties and Problem IdentificationMaster dynamic programming from scratch — what DP really is, the two essential properties (overlapping subproblems and optimal substructure), how to identify a DP problem, the four-step DP recipe, comparison with divide-and-conquer and greedy, and a taxonomy of DP problem types.02Dynamic ProgrammingFibonacci DP — From Exponential to Linear with Memoization and Matrix ExponentiationMaster Fibonacci and Fibonacci-like problems with dynamic programming — naive recursion O(2^n), memoization O(n), tabulation O(n), space-optimized O(1) space, matrix exponentiation O(log n), and classic DP problems that reduce to Fibonacci variants like climbing stairs, house robber, and tile tiling.03Dynamic ProgrammingKnapsack Problem — 0/1, Unbounded, and Fractional with Complete AnalysisMaster all knapsack variants — 0/1 knapsack with 2D and 1D DP tables, unbounded knapsack with reusable items, fractional knapsack with greedy, subset sum, partition equal subset sum, and the general framework for recognizing knapsack problems in interviews.04Dynamic ProgrammingLongest Common Subsequence — Complete Guide with DP Table and String VariantsMaster Longest Common Subsequence (LCS) completely — definition with clear examples, 2D DP table construction, string reconstruction, space optimization, and all important variants including Longest Common Substring, Edit Distance, Shortest Common Supersequence, and real-world applications.