Strategies for Getting Unstuck

Here are battle-tested strategies for every type of being stuck.

Strategy 1: Start with Brute Force

When to use: You have no idea where to start.

How:

  1. Ignore efficiency completely
  2. Think: "How would a computer solve this the dumb way?"
  3. Code that solution
  4. Optimize later

Example - Two Sum:

# Start here (even though it's O(n²))
def two_sum(nums, target):
    # Check every pair - simple and clear
    for i in range(len(nums)):
        for j in range(i + 1, len(nums)):
            if nums[i] + nums[j] == target:
                return [i, j]
    return []

# Then optimize to O(n)
def two_sum_optimized(nums, target):
    seen = {}
    for i, num in enumerate(nums):
        if target - num in seen:
            return [seen[target - num], i]
        seen[num] = i
    return []

Why this works:

  • Gets you started (momentum is everything)
  • Shows you understand the problem
  • Gives you something to optimize
  • Demonstrates problem-solving process

Strategy 2: Solve a Simpler Version

When to use: Problem feels overwhelming.

How:

  1. Remove constraints
  2. Reduce input size
  3. Add restrictions
  4. Solve the easier version
  5. Gradually add complexity back

Example - Edit Distance:

# Original: Find minimum edits to transform word1 to word2

# Simpler version 1: What if we can only insert?
def min_inserts(s1, s2):
    return len(s2) - len(s1)

# Simpler version 2: What if strings are length 1?
def edit_distance_base(s1, s2):
    if s1 == s2:
        return 0
    return 1

# Simpler version 3: What if one string is empty?
def edit_distance_base_case(s1, s2):
    if not s1:
        return len(s2)
    if not s2:
        return len(s1)

# Now build up to full solution...

Progressive simplification:

  • String → Array → Single element
  • All operations → One operation
  • General case → Specific case
  • Dynamic → Static

Strategy 3: Work Through Examples Manually

When to use: You have an idea but can't implement it.

How:

  1. Choose a small example
  2. Solve it by hand step-by-step
  3. Write down every decision you make
  4. Notice the pattern
  5. Code that pattern

Example - Valid Parentheses:

Input: "([{}])"

Manual steps:
1. See '(' - need to match with ')' later - save it
2. See '[' - need to match with ']' later - save it
3. See '{' - need to match with '}' later - save it
4. See '}' - must match most recent unmatched ('{') ✓
5. See ']' - must match most recent unmatched ('[') ✓
6. See ')' - must match most recent unmatched ('(') ✓

Pattern noticed: Last opened, first closed → Stack!

Then code:

def is_valid(s):
    stack = []
    pairs = {'(': ')', '[': ']', '{': '}'}

    for char in s:
        if char in pairs:  # Opening
            stack.append(char)
        else:  # Closing
            if not stack or pairs[stack.pop()] != char:
                return False

    return len(stack) == 0

Strategy 4: Change Your Perspective

When to use: Current approach isn't working.

How:

Perspective 1: Think about Data Structure

Current: "I need to search for elements"
New: "What data structure gives fast search? → Hash map/set"

Perspective 2: Think about What You're Tracking

Current: "I need to find the maximum"
New: "I'm tracking the max seen so far → One variable"

Perspective 3: Think about Constraints

Current: "I need to check all possibilities"
New: "Wait, sorted input → Binary search possible"

Perspective 4: Think About the End State

Current: "How do I start?"
New: "Work backwards - what would the answer look like?"

Example - House Robber:

# Perspective 1: "What do I need to decide at each house?"
# → Include/exclude decision → Recursion/DP

# Perspective 2: "What info do I need from previous houses?"
# → Max money from previous two houses

# Perspective 3: "Can I derive current from previous?"
# → Yes: dp[i] = max(dp[i-1], dp[i-2] + nums[i])

def rob(nums):
    if len(nums) <= 2:
        return max(nums) if nums else 0

    prev2, prev1 = nums[0], max(nums[0], nums[1])

    for i in range(2, len(nums)):
        current = max(prev1, prev2 + nums[i])
        prev2, prev1 = prev1, current

    return prev1

Strategy 5: Ask for a Hint (The Right Way)

When to use: After 10-15 minutes of genuine effort.

Don't say:

  • ❌ "I have no idea"
  • ❌ "Just tell me the answer"
  • ❌ "Is it dynamic programming?"

Do say:

  • ✅ "I've tried X and Y. Could you give me a hint about the approach?"
  • ✅ "I'm thinking about using a hash map, but I'm stuck on how to handle duplicates. Any hints?"
  • ✅ "I have an O(n²) solution. Is there a way to optimize this?"

Good hint requests show:

  • What you've tried
  • Where you're stuck specifically
  • That you've made genuine effort

Strategy 6: Rubber Duck Debugging

When to use: Code almost works but something's wrong.

How:

  1. Explain your code line-by-line out loud
  2. Trace through with an example
  3. Say what you expect at each step
  4. Notice where reality differs from expectation

Example:

You: "So first I create a hash map... then I iterate through nums.
     For index 0, value 2, I calculate target minus 2 which is 7.
     I check if 7 is in the map... it's not, so I add 20.

     Wait... I'm adding the value as the key. But then when I look
     up target - num, I need to find the index, not the value!
     Oh, I should be storing num → index, not index → num!"

Strategy 7: Binary Search Your Code

When to use: Code fails but you don't know where.

How:

  1. Add a print statement in the middle
  2. Check if it's correct up to that point
  3. If yes, bug is in second half
  4. If no, bug is in first half
  5. Repeat until you find the exact line

Example:

def binary_search(nums, target):
    left, right = 0, len(nums) - 1

    while left <= right:
        print(f"Checking range [{left}, {right}]")  # Debug
        mid = (left + right) // 2
        print(f"Mid = {mid}, value = {nums[mid]}")   # Debug

        if nums[mid] == target:
            return mid
        elif nums[mid] < target:
            left = mid + 1
        else:
            right = mid - 1

    return -1

Strategy 8: Pattern Recognition

When to use: Problem reminds you of something but you can't place it.

Common patterns:

"Find all combinations" → Backtracking
"Shortest path" → BFS
"Longest/shortest substring with condition" → Sliding window
"Count ways to..." → DP
"Find in sorted array" → Binary search
"Track min/max efficiently" → Heap or monotonic stack
"Group/count frequencies" → Hash map
"Unique elements" → Set
"Recent items" → Queue
"Undo operations" → Stack

Strategy 9: Component Testing

When to use: Complex solution with multiple parts.

How:

  1. Test each function separately
  2. Verify each component works in isolation
  3. Then test integration

Example:

# Test helper separately
def is_palindrome(s):
    return s == s[::-1]

# Test: is_palindrome("aba") → True
# Test: is_palindrome("abc") → False

# Then use in main function
def partition(s):
    result = []

    def backtrack(start, current):
        if start == len(s):
            result.append(current[:])
            return

        for end in range(start + 1, len(s) + 1):
            substring = s[start:end]
            if is_palindrome(substring):  # Using tested helper
                current.append(substring)
                backtrack(end, current)
                current.pop()

    backtrack(0, [])
    return result

Strategy 10: The 80/20 Solution

When to use: Time is running out.

How:

  1. Solve the main case that covers 80% of situations
  2. Acknowledge edge cases exist
  3. Show you know what's missing

Example:

def solution(arr):
    # Handle the main case
    result = process_main_case(arr)

    # Acknowledge what's missing:
    # "This doesn't handle negative numbers yet, but we could
    #  add a check at the start to handle those separately"

    return result

Emergency Strategies

If you're at 30+ minutes and really stuck:

1. Verbalize the struggle:

"I'm finding this challenging. Let me try a different angle..."

2. Ask for guidance:

"Would it help if I explained my thought process so far?"

3. Pivot to what you know:

"I'm stuck on the optimal solution, but let me show you
 the brute force approach to prove I understand the problem..."

4. Show meta-problem-solving:

"In a real scenario, I'd look at similar problems in the
 codebase or discuss with teammates. Could we do that here?"

Key Takeaway

Getting unstuck is a skill, not luck. The best engineers don't get stuck less—they get unstuck faster. They try multiple strategies, communicate constantly, and aren't afraid to change approaches. Practice these strategies and you'll spend less time stuck and more time solving.