You’ve been grinding LeetCode problems every day for weeks or even months. You’ve watched countless YouTube tutorials, read all the recommended books, and even joined study groups. Yet when you face those medium-level problems, you still freeze up. Sound familiar?

If you’re nodding along, you’re not alone. Many aspiring developers find themselves stuck in this frustrating plateau despite putting in consistent effort. In this comprehensive guide, we’ll explore why you might be struggling and, more importantly, how to break through this barrier.

The Common Struggle With Medium LeetCode Problems

Let’s start by acknowledging a harsh truth: solving algorithm problems is hard. It’s not supposed to be easy, especially at the medium and hard levels. But the difference between those who eventually break through and those who remain stuck often isn’t raw intelligence or coding experience—it’s their approach to learning and practice.

Here’s what typically happens:

This cycle is demoralizing, but understanding why it happens is the first step to overcoming it.

7 Reasons You’re Still Struggling With Medium Problems

1. You’re Not Building The Right Mental Models

One of the biggest reasons programmers struggle with medium LeetCode problems is that they’re trying to memorize solutions rather than understanding the underlying patterns and building mental models.

Think of it this way: if you only memorize the solution to “Two Sum,” you’ve learned to solve exactly one problem. But if you understand the pattern of using a hash map to track values you’ve seen before, you’ve gained a tool that applies to dozens of problems.

Mental models are frameworks that help you approach and break down problems. They’re like templates your brain can quickly adapt to new situations. Without these models, each new problem feels like starting from scratch.

2. You’re Rushing Through Problems

In the age of “grinding LeetCode,” there’s pressure to solve as many problems as possible. This quantity-over-quality approach often leads to superficial understanding.

If you look at the solution after just 10-15 minutes of struggle, you’re robbing yourself of the most valuable part of the learning process: the struggle itself. The mental connections formed during that struggle are what build lasting problem-solving abilities.

Consider this research-backed learning principle: we learn better when we retrieve information from memory rather than simply reviewing it. This is called the “retrieval practice” effect. By giving up too quickly, you’re missing out on this powerful learning mechanism.

3. You’re Not Reviewing Problems Effectively

Many programmers solve a problem, feel good about it, and never look back. But one-time exposure is rarely enough to cement understanding, especially for complex concepts.

Effective learning requires spaced repetition—returning to problems after increasing intervals of time. Without this systematic review, you’re likely forgetting solutions almost as quickly as you’re learning them.

Research shows that we forget approximately 70% of what we learn within 24 hours without proper review. By day 30, without any reinforcement, we retain only about 2-3% of the original information.

4. You Haven’t Mastered The Fundamentals

Medium problems typically combine multiple fundamental concepts. If your understanding of these basics is shaky, you’ll struggle when they’re combined in new and complex ways.

For example, a medium-level dynamic programming problem might require solid understanding of:

If any of these foundations is weak, the entire solution becomes difficult to construct.

5. You’re Not Actively Coding Solutions

Reading solutions and watching tutorials creates an illusion of understanding. You follow along, nodding in agreement, thinking “this makes sense.” But passive consumption is very different from active creation.

Many learners fall into the trap of reading multiple solutions or watching several tutorials without actually implementing the code themselves. This passive learning gives a false sense of mastery that quickly evaporates when facing a blank editor.

6. You Haven’t Developed A Systematic Approach

Successful problem solvers don’t just dive into coding. They have a systematic approach:

  1. Understanding the problem completely
  2. Working through examples manually
  3. Looking for patterns and edge cases
  4. Considering multiple approaches before coding
  5. Testing their solution with various inputs

Without this structured method, you might find yourself jumping between partial solutions or getting stuck in unproductive thought loops.

7. You’re Dealing With Psychological Barriers

Finally, don’t underestimate the psychological aspects of problem-solving. Many programmers develop mental blocks around certain problem types or experience “solution paralysis” when faced with a blank editor.

Imposter syndrome, anxiety about time constraints, and fear of failure can all interfere with your cognitive processes. These psychological barriers can be just as limiting as knowledge gaps.

How To Break Through The Medium Problem Barrier

Now that we understand the common roadblocks, let’s explore practical strategies to overcome them and level up your problem-solving skills.

Focus On Patterns, Not Problems

Instead of treating each problem as a unique challenge, start grouping them into pattern categories. Here’s a framework to get started:

Core Patterns To Master:

When you encounter a new problem, try to identify which pattern it matches before diving into the solution. With practice, this pattern recognition becomes faster and more intuitive.

For example, consider these medium problems and their patterns:

Problem Pattern
Longest Substring Without Repeating Characters Sliding Window + Hash Map
3Sum Two Pointers
Number of Islands DFS/BFS on Grid
Coin Change Dynamic Programming

Implement The 20-50-30 Rule

To structure your practice more effectively, follow the 20-50-30 rule:

Here’s how to apply this in practice:

The 20% Phase: Problem Understanding

  1. Read the problem statement multiple times
  2. Work through the examples manually to understand the expected output
  3. Identify edge cases (empty arrays, negative numbers, etc.)
  4. Determine what pattern category this problem might fall into
  5. Sketch a high-level approach before writing any code

The 50% Phase: Productive Struggle

  1. Attempt to implement your solution without looking at hints
  2. If you get stuck, take a short break and return with fresh eyes
  3. Try to solve simpler versions of the problem first
  4. Use debugging tools to understand where your solution fails
  5. Only move to hints if you’ve been truly stuck for 30+ minutes

The 30% Phase: Review and Internalize

  1. Compare your solution to the official solution
  2. Understand any optimizations you missed
  3. Reimplement the solution from memory the next day
  4. Document the key insights in your own words
  5. Add the problem to your spaced repetition system for future review

Build A Deliberate Review System

Spaced repetition is crucial for long-term retention. Here’s how to implement it for algorithm problems:

Create A Review Schedule:

You can use tools like Anki or simply maintain a spreadsheet with problem details and review dates. The key is consistency and actually implementing the solutions again rather than just reading them.

For Each Review, Ask Yourself:

Master One Pattern At A Time

Rather than jumping between different problem types, focus on mastering one pattern category at a time. This approach builds deeper understanding and confidence.

For Example, A Sliding Window Deep Dive:

  1. Start with basic fixed-length window problems
  2. Move to variable-length windows with simple conditions
  3. Progress to more complex window conditions
  4. Tackle problems combining sliding window with other techniques

Spend at least a week on each pattern category, solving 5-10 problems of increasing difficulty. Only move on when you can comfortably solve new problems using that pattern without hints.

Verbalize Your Thought Process

One powerful technique used by expert problem solvers is thinking aloud. This forces you to clarify your reasoning and often reveals gaps in your understanding.

Try these approaches:

This practice not only improves your problem-solving but also prepares you for technical interviews where communicating your approach is crucial.

Implement The “Solve It Three Ways” Challenge

For medium problems you’ve solved, challenge yourself to implement three different solutions:

  1. A brute force approach (to ensure you understand the problem basics)
  2. An optimized solution using the appropriate pattern
  3. A different approach using an alternative technique

This exercise forces you to think beyond your first solution and deepens your understanding of the problem space.

For example, for the “Maximum Subarray” problem:

Use Code Templates Strategically

Having code templates for common patterns can accelerate your learning and reduce cognitive load when solving new problems. Here’s a simple template for the sliding window pattern:

function slidingWindowTemplate(s) {
    let windowStart = 0;
    let result = 0;
    let windowData = {}; // or other data structure to track window state
    
    for (let windowEnd = 0; windowEnd < s.length; windowEnd++) {
        // Add the current element to window data
        let rightChar = s[windowEnd];
        // Update window data
        
        // Condition to shrink window
        while (/* condition to shrink window */) {
            // Remove the leftmost element from window data
            let leftChar = s[windowStart];
            // Update window data
            windowStart++;
        }
        
        // Update result based on current window
        result = Math.max(result, windowEnd - windowStart + 1);
    }
    
    return result;
}

The key is not to copy-paste these templates blindly but to understand the underlying structure and adapt it to each specific problem.

Tackling Specific Problem Types That Give You Trouble

Let’s look at strategies for some of the most challenging problem categories that trip up intermediate programmers.

Dynamic Programming Problems

Dynamic programming (DP) problems are notoriously difficult for many programmers. Here’s a systematic approach:

1. Identify The Subproblems

Every DP problem can be broken down into overlapping subproblems. Ask yourself:

2. Define The State Variables

State variables represent the information you need to track. For example:

3. Formulate The Recurrence Relation

This is the heart of DP—how the solution to the current problem relates to solutions of subproblems. Usually takes the form:

dp[i][j] = some_operation(dp[i-1][j], dp[i][j-1], etc.)

4. Identify The Base Cases

These are the simplest scenarios where the answer is directly known without calculation:

5. Decide Implementation Approach

Sample DP Problem Walkthrough: Coin Change

Let’s apply this framework to the classic Coin Change problem: Given coins of different denominations and a total amount, find the fewest coins needed to make that amount.

  1. Subproblems: For each amount from 0 to target, find minimum coins needed
  2. State variable: Current amount (amount)
  3. Recurrence relation: dp[amount] = 1 + min(dp[amount – coin]) for each coin
  4. Base case: dp[0] = 0 (zero coins needed for amount zero)
  5. Implementation: Bottom-up approach
function coinChange(coins, amount) {
    // Initialize dp array with amount+1 (which is greater than max possible coins)
    const dp = Array(amount + 1).fill(amount + 1);
    
    // Base case: 0 coins needed for amount 0
    dp[0] = 0;
    
    // Build up the solution
    for (let currentAmount = 1; currentAmount <= amount; currentAmount++) {
        for (const coin of coins) {
            if (coin <= currentAmount) {
                dp[currentAmount] = Math.min(dp[currentAmount], 1 + dp[currentAmount - coin]);
            }
        }
    }
    
    return dp[amount] > amount ? -1 : dp[amount];
}

Graph Problems

Graph problems often intimidate programmers, but they become manageable with a structured approach:

1. Understand The Graph Representation

Decide how to represent the graph:

2. Choose The Right Traversal Strategy

3. Track Visited Nodes

Always keep track of visited nodes to avoid cycles and redundant work.

4. Consider Special Graph Algorithms

For specific problems, specialized algorithms may be needed:

Sample Graph Problem Approach: Number of Islands

Let’s see how to approach the Number of Islands problem: Given a 2D grid where ‘1’ represents land and ‘0’ represents water, count the number of islands.

function numIslands(grid) {
    if (!grid || grid.length === 0) return 0;
    
    const rows = grid.length;
    const cols = grid[0].length;
    let islandCount = 0;
    
    function dfs(r, c) {
        // Check boundaries and if it's land
        if (r < 0 || c < 0 || r >= rows || c >= cols || grid[r][c] === '0') {
            return;
        }
        
        // Mark as visited by changing to '0'
        grid[r][c] = '0';
        
        // Explore all 4 directions
        dfs(r + 1, c);
        dfs(r - 1, c);
        dfs(r, c + 1);
        dfs(r, c - 1);
    }
    
    // Traverse the grid
    for (let r = 0; r < rows; r++) {
        for (let c = 0; c < cols; c++) {
            if (grid[r][c] === '1') {
                islandCount++;
                dfs(r, c); // Sink the entire island
            }
        }
    }
    
    return islandCount;
}

Psychological Strategies For Overcoming Mental Blocks

The mental aspect of problem-solving is just as important as the technical knowledge. Here are strategies to overcome psychological barriers:

Embrace The Struggle

Reframe how you view difficulty. Struggling with problems isn’t a sign of inadequacy—it’s an essential part of the learning process. Research in cognitive science calls this “desirable difficulty”—challenges that enhance long-term learning.

When you encounter a difficult problem, try saying: “This is difficult, and that’s good. My brain is forming new connections right now.”

Use Time-Boxing

Set a fixed time limit for your initial attempt at a problem (e.g., 30-45 minutes). This prevents endless frustration while ensuring you give yourself enough time to struggle productively.

After the time box:

Practice Metacognition

Metacognition—thinking about your thinking—can help identify patterns in how you approach problems:

Keep a “problem journal” where you not only document solutions but also reflect on your problem-solving process and emotional responses.

Build A Growth Mindset Community

The people you surround yourself with significantly impact your mindset. Find a community that:

This could be an online forum, a local meetup, or a study group with colleagues.

Creating A Structured Learning Path

To make consistent progress, you need a structured approach rather than randomly picking problems. Here’s a 12-week plan to systematically improve your medium-level problem-solving skills:

Week 1-2: Foundation Strengthening

Week 3-4: Array and String Patterns

Week 5-6: Tree and Graph Traversal

Week 7-8: Dynamic Programming Foundations

Week 9-10: Advanced Patterns

Week 11-12: Integration and Mock Interviews

For each week, follow this daily structure:

Leveraging AI Tools Effectively

Modern AI tools can be powerful allies in your learning journey if used correctly. Here’s how to leverage them without becoming dependent:

For Concept Understanding

Use AI to explain concepts in multiple ways. For example, if you’re struggling with dynamic programming:

For Solution Review

After implementing your own solution:

For Targeted Hints

When stuck, ask for progressive hints rather than full solutions:

For Custom Problem Generation

Use AI to create variations of problems you’ve solved:

Conclusion: The Path Forward

Breaking through the medium problem barrier isn’t about raw intelligence or memorizing more solutions—it’s about developing a structured approach to learning and problem-solving. By focusing on patterns rather than individual problems, building effective mental models, and implementing consistent review systems, you can systematically improve your algorithm skills.

Remember that everyone—even the most accomplished engineers—struggled with these concepts at some point. The difference is in how they approached that struggle and used it as a catalyst for growth rather than a source of discouragement.

Your daily practice isn’t wasted effort—it’s building neural pathways that will eventually connect into powerful problem-solving capabilities. By applying the strategies in this guide, you can transform that daily practice into meaningful progress.

The journey from struggling with medium problems to solving them confidently isn’t a straight line—it’s a series of plateaus, breakthroughs, and occasional setbacks. Embrace this journey with patience and persistence, and you’ll not only conquer LeetCode mediums but develop problem-solving skills that will serve you throughout your programming career.

What specific pattern or problem type will you focus on mastering first? Start there, apply these principles consistently, and watch as previously challenging problems begin to yield to your improved approach.