How to Approach Problems
How to Approach Problems
Staring at a coding problem and not knowing where to start? You're not alone. The difference between struggling for hours and solving problems efficiently comes down to one thing: having a systematic approach.
This tutorial will teach you a proven framework that works for any data structures and algorithms problem.
Goal: Learn a step-by-step method to approach and solve any problem confidently.
Key Insight: Most people fail not because they lack knowledge, but because they lack a systematic approach. A good framework makes even hard problems manageable.
The 7-Step Problem-Solving Framework
Follow these steps for every problem:
Step 1: Understand the Problem
Step 2: Explore Examples
Step 3: Break It Down
Step 4: Solve a Simpler Version
Step 5: Implement the Solution
Step 6: Test and Debug
Step 7: Optimize
Let's explore each step in detail.
Step 1: Understand the Problem
Time to spend: 2-3 minutes
Goal: Fully understand what you're being asked to do
Questions to Ask:
- ›
What are the inputs?
- ›What type? (array, string, number, graph, etc.)
- ›What size? (constraints)
- ›What values? (range, negatives allowed?, duplicates?)
- ›
What are the outputs?
- ›Return value type
- ›Format (single value, array, boolean, etc.)
- ›
What are the constraints?
- ›Time limit
- ›Space limit
- ›Edge cases
- ›
Can I restate the problem in my own words?
- ›If you can't explain it simply, you don't understand it
Example Problem:
Problem: "Find the maximum sum of any contiguous subarray"
Understanding Phase:
- ›Input: Array of integers (can be negative)
- ›Output: Single integer (the maximum sum)
- ›Constraints: Array length 1 to 10^5
- ›Restate: Find a slice of the array where the sum of elements is highest
Questions to clarify:
- ›Can array have all negative numbers? (Yes)
- ›Is empty array possible? (No, at least 1 element)
- ›What if array has one element? (Return that element)
Step 2: Explore Examples
Time to spend: 3-5 minutes
Goal: Understand the problem through concrete cases
Types of Examples to Consider:
- ›Simple example - Small, easy to trace
- ›Complex example - Larger, tests your understanding
- ›Edge cases - Boundary conditions
- ›Invalid inputs - What if inputs don't meet constraints?
Example Problem: Maximum Subarray Sum
Input: [2, -1, 3, -2, 5]
Examples to trace:
Example 1 - Simple:
Input: [2, -1, 3]
Possible subarrays:
[2] → sum = 2
[-1] → sum = -1
[3] → sum = 3
[2, -1] → sum = 1
[-1, 3] → sum = 2
[2, -1, 3] → sum = 4
Maximum: 4
Example 2 - All negative:
Input: [-5, -2, -8, -1]
Maximum single element: -1
Output: -1
Example 3 - Single element:
Input: [5]
Output: 5
Example 4 - Complex:
Input: [2, -1, 3, -2, 5]
Best subarray: [2, -1, 3, -2, 5] → sum = 7
Output: 7
Step 3: Break It Down
Time to spend: 2-3 minutes
Goal: Write pseudocode or outline
Breaking Down the Problem:
- ›Write the function signature
- ›Outline the main steps in comments
- ›Identify data structures needed
- ›Note any helper functions
Example: Maximum Subarray Sum
1def max_subarray_sum(arr):
2 # Step 1: Handle edge case - single element
3
4 # Step 2: Initialize variables
5 # - max_sum: track best sum found
6 # - current_sum: track current subarray sum
7
8 # Step 3: Iterate through array
9 # - Add element to current_sum
10 # - Update max_sum if needed
11 # - Reset current_sum if it goes negative
12
13 # Step 4: Return max_sum
14
15 passBenefits:
- ›Catches logical errors before coding
- ›Gives you a roadmap to follow
- ›Makes interviews smoother (show your thinking)
Step 4: Solve a Simpler Version
Time to spend: 5-10 minutes
Goal: Solve the problem ignoring some constraints
Simplification Strategies:
- ›Use brute force - Don't worry about efficiency yet
- ›Reduce input size - Solve for array of 3 elements
- ›Remove constraints - Assume all positive numbers
- ›Use extra space - Don't worry about O(1) space yet
Example: Maximum Subarray Sum (Brute Force)
1def max_subarray_sum_brute(arr):
2 n = len(arr)
3 max_sum = float('-inf')
4
5 # Try all possible subarrays
6 for i in range(n):
7 for j in range(i, n):
8 # Calculate sum of subarray arr[i:j+1]
9 current_sum = sum(arr[i:j+1])
10 max_sum = max(max_sum, current_sum)
11
12 return max_sum
13
14# Time: O(n³) - Very slow!
15# Space: O(1)
16# But it works correctly!Why brute force first?
- ›Validates your understanding
- ›Provides a baseline solution
- ›Helps you identify what to optimize
Step 5: Implement the Solution
Time to spend: 10-15 minutes
Goal: Write clean, working code
Implementation Tips:
- ›Start with the simpler solution from Step 4
- ›Use clear variable names (not x, y, z)
- ›Add comments for complex logic
- ›Handle edge cases as you go
- ›Think about optimization as you write
Example: Optimized Solution (Kadane's Algorithm)
1def max_subarray_sum(arr):
2 # Edge case: empty array (shouldn't happen per constraints)
3 if not arr:
4 return 0
5
6 # Initialize with first element
7 max_sum = arr[0]
8 current_sum = arr[0]
9
10 # Iterate from second element
11 for i in range(1, len(arr)):
12 # Either extend current subarray or start new one
13 current_sum = max(arr[i], current_sum + arr[i])
14
15 # Update maximum if needed
16 max_sum = max(max_sum, current_sum)
17
18 return max_sum
19
20# Time: O(n) - Much better!
21# Space: O(1)
22
23# Test
24print(max_subarray_sum([2, -1, 3, -2, 5])) # Output: 7
25print(max_subarray_sum([-5, -2, -8, -1])) # Output: -1Key Insight: By keeping track of current_sum, we avoid recalculating sums. If current_sum becomes negative, we start fresh (because adding a negative makes things worse).
Step 6: Test and Debug
Time to spend: 5-10 minutes
Goal: Verify correctness with various inputs
Test Cases to Run:
- ›Example cases from Step 2
- ›Edge cases:
- ›Empty input
- ›Single element
- ›All same values
- ›Minimum/maximum values
- ›Your custom cases
Debugging Strategy:
If you get wrong output:
- ›Print intermediate values
- ›Trace through manually with a small example
- ›Check loop boundaries (off-by-one errors)
- ›Verify edge case handling
Example: Testing Maximum Subarray
1def test_max_subarray():
2 # Test 1: Regular case
3 assert max_subarray_sum([2, -1, 3, -2, 5]) == 7
4
5 # Test 2: All negative
6 assert max_subarray_sum([-5, -2, -8, -1]) == -1
7
8 # Test 3: Single element
9 assert max_subarray_sum([5]) == 5
10
11 # Test 4: All positive
12 assert max_subarray_sum([1, 2, 3, 4]) == 10
13
14 # Test 5: Alternating signs
15 assert max_subarray_sum([1, -3, 2, -1, 3]) == 4
16
17 print("All tests passed!")
18
19test_max_subarray()Step 7: Optimize
Time to spend: Variable (if needed)
Goal: Make your solution more efficient
Optimization Checklist:
Time Complexity:
- ›Can I eliminate redundant calculations?
- ›Can I use a better data structure? (hash map, heap, etc.)
- ›Can I use a different algorithm? (divide and conquer, dynamic programming)
Space Complexity:
- ›Can I reuse the input array?
- ›Can I use constant space instead of extra arrays?
- ›Can I avoid recursion to save stack space?
Code Quality:
- ›Can I make variable names clearer?
- ›Can I extract repeated logic into functions?
- ›Can I simplify complex conditionals?
Optimization Example: From O(n³) to O(n)
We already optimized maximum subarray from brute force O(n³) to Kadane's algorithm O(n). Here's the progression:
Version 1: O(n³) - Triple nested loop
Version 2: O(n²) - Calculate sums incrementally
Version 3: O(n) - Kadane's algorithm (keep running sum)
Complete Example: Two Sum Problem
Let's apply the entire framework to a classic problem.
Problem Statement
Given: An array of integers and a target sum
Find: Indices of two numbers that add up to target
Constraint: Each input has exactly one solution, can't use same element twice
Step 1: Understand
- ›Input: Array of integers, target integer
- ›Output: Array of two indices
- ›Restate: Find positions i and j where arr[i] + arr[j] = target
Step 2: Examples
Input: [2, 7, 11, 15], target = 9
Output: [0, 1] (because 2 + 7 = 9)
Input: [3, 2, 4], target = 6
Output: [1, 2] (because 2 + 4 = 6)
Input: [3, 3], target = 6
Output: [0, 1]
Step 3: Break It Down
1def two_sum(nums, target):
2 # Approach: Use hash map to store complements
3
4 # Step 1: Create hash map to store value → index
5
6 # Step 2: Iterate through array
7 # - Calculate complement (target - current)
8 # - Check if complement exists in hash map
9 # - If yes: return [complement_index, current_index]
10 # - If no: add current to hash map
11
12 # Step 3: Return result
13 passStep 4: Brute Force Solution
1def two_sum_brute(nums, target):
2 n = len(nums)
3
4 # Try all pairs
5 for i in range(n):
6 for j in range(i + 1, n):
7 if nums[i] + nums[j] == target:
8 return [i, j]
9
10 return []
11
12# Time: O(n²)
13# Space: O(1)Step 5: Optimized Solution
1def two_sum(nums, target):
2 # Hash map: value → index
3 seen = {}
4
5 for i, num in enumerate(nums):
6 complement = target - num
7
8 # Check if complement exists
9 if complement in seen:
10 return [seen[complement], i]
11
12 # Store current number
13 seen[num] = i
14
15 return []
16
17# Time: O(n)
18# Space: O(n)
19
20# Test
21print(two_sum([2, 7, 11, 15], 9)) # [0, 1]
22print(two_sum([3, 2, 4], 6)) # [1, 2]Step 6: Test
All tests pass! The hash map solution correctly handles all cases.
Step 7: Optimize
Already optimized from O(n²) to O(n) using a hash map. Can't do better than O(n) since we must look at each element at least once.
Common Problem Patterns
Recognizing patterns helps you choose the right approach faster.
Pattern 1: Two Pointers
When to use: Sorted array, finding pairs, palindromes
Example: Find if array has two numbers that sum to target (sorted array)
1def two_sum_sorted(arr, target):
2 left = 0
3 right = len(arr) - 1
4
5 while left < right:
6 current_sum = arr[left] + arr[right]
7
8 if current_sum == target:
9 return [left, right]
10 elif current_sum < target:
11 left += 1
12 else:
13 right -= 1
14
15 return []
16
17# Time: O(n), Space: O(1)Pattern 2: Sliding Window
When to use: Contiguous subarrays, substrings, fixed/variable window size
Example: Maximum sum of k consecutive elements
1def max_sum_k_elements(arr, k):
2 # Initial window
3 window_sum = sum(arr[:k])
4 max_sum = window_sum
5
6 # Slide window
7 for i in range(k, len(arr)):
8 window_sum = window_sum - arr[i - k] + arr[i]
9 max_sum = max(max_sum, window_sum)
10
11 return max_sum
12
13# Time: O(n), Space: O(1)Pattern 3: Fast and Slow Pointers
When to use: Linked lists, cycle detection, finding middle
Example: Detect cycle in linked list (concept)
Fast pointer moves 2 steps, slow moves 1 step
If they meet, there's a cycle
Pattern 4: Hash Map/Set
When to use: Looking up values, counting occurrences, finding duplicates
Example: Find first duplicate
1def first_duplicate(arr):
2 seen = set()
3
4 for num in arr:
5 if num in seen:
6 return num
7 seen.add(num)
8
9 return -1
10
11# Time: O(n), Space: O(n)Pattern 5: Divide and Conquer
When to use: Can split problem into independent subproblems
Examples: Merge sort, binary search, quick sort
Problem-Solving Tips
Tip 1: Don't Rush to Code
Spend time understanding and planning. 5 minutes of planning saves 30 minutes of debugging.
Tip 2: Start Simple
Brute force is better than no solution. You can optimize later.
Tip 3: Talk Through Your Thinking
In interviews, explain your approach. Interviewers want to see your thought process.
Tip 4: Draw Diagrams
Visualize the problem. Draw arrays, trees, graphs, or state transitions.
Tip 5: Look for Patterns
Similar problems often have similar solutions. Build a mental library of patterns.
Tip 6: Test As You Go
Don't wait until the end to test. Verify each part works as you build it.
Tip 7: Ask Questions
Clarify ambiguities before coding. It's better to ask than to solve the wrong problem.
When You're Stuck
Strategy 1: Solve a Smaller Version
Can't handle array of size n? Try n = 3 first.
Strategy 2: Work Backwards
Start from the desired output and work back to the input.
Strategy 3: Look for Similar Problems
Have you solved something similar? Can you adapt that approach?
Strategy 4: Try a Different Data Structure
Hash map not working? Try a heap, queue, or stack.
Strategy 5: Take a Break
Step away for 5 minutes. Fresh perspective helps.
Key Takeaways
The 7-Step Framework:
- ›Understand the problem
- ›Explore examples
- ›Break it down
- ›Solve simpler version
- ›Implement solution
- ›Test and debug
- ›Optimize
Core Principles:
- ›Plan before you code
- ›Start with brute force
- ›Test early and often
- ›Recognize common patterns
- ›Communicate your thinking
Success Formula: Understanding + Strategy + Practice = Problem-Solving Mastery
What's Next?
Now that you have a problem-solving framework:
- ›Array Problems - Practice the framework on array problems
- ›String Problems - Apply to string manipulation
- ›Two Pointers Pattern - Master common patterns
Practice Problem
Apply the 7-step framework to this problem:
Problem: Given a sorted array, remove duplicates in-place such that each element appears only once. Return the new length.
Example:
Input: [1, 1, 2, 2, 3, 4, 4]
Output: 4 (array becomes [1, 2, 3, 4, _, _, _])
Your turn: Work through steps 1-7!
Hint: Two pointers pattern works well here.
Congratulations! You now have a systematic approach to solve any problem. Practice this framework on every problem you encounter!