Red-Green-Code

Deliberate practice techniques for software developers

  • Home
  • About
  • Contact
  • Project 462
  • CP FAQ
  • Newsletter

2023 in Review: 50 LeetCode Tips

By Duncan Smith Leave a Comment Dec 27 0

a programmer working at a computer

Let’s review the 50 LeetCode tips from the past year.

Fundamentals of LeetCode Practice

Coding interviews

Many software companies use a coding interview as part of their hiring process. Candidates are asked to solve algorithmic coding problems on the fly. Since this isn’t something programmers practice much in their jobs, or even in school, practice is required. LeetCode provides the right kinds of problems, along with learning materials, an active community, and an easy-to-use online judge.

Topics

Each LeetCode problem is associated with one or more topics, such as hash tables, sorting, and binary search. Learning about the topics helps you solve the problems, and practicing the problems helps you understand the topics. Our first goal is, given a topic, to learn how to solve LeetCode problems for that topic.

Model problems

To learn how to solve problems for a topic, I suggest the model problem/solution approach. Rather than learning a topic in isolation, pick a problem that uses that topic and learn every detail required to solve that problem. A model problem is right for this purpose if it focuses primarily on the topic you’re learning and has the appropriate difficulty for your current skill level. Learn enough model problems for each topic that you cover the key ideas for that topic.

Model solutions

For each of your model problems, create a model solution containing your best solution for that problem, based on your own attempts and other solutions that you find in your research. Explain your model solution using code, code comments, written explanations, and diagrams. If you have trouble during a practice session, take that as a sign that you should make a part of your model solution clearer. To ensure that you include all the relevant details in each model solution, use a template to write it.

Spaced repetition

No matter how carefully you select your model problem and write up your model solution, you will only be able to solve it on demand (as in a coding interview) if you practice solving it from scratch. The best way to practice is spaced repetition. This means practicing a problem, waiting for an interval, practicing it again, and repeating that process until you master it. After each repetition, decide based on your performance whether you should increase or decrease the repetition interval, and by how much. An exponential series (1 day, 2 days, 4 days, 8 days, etc.) works well as a rule of thumb for repetition interval lengths.

Although spaced repetition is often associated with memorization, that isn’t its purpose when you use it for problem-solving practice. Instead, during each repetition, think about updating your model solution so it’s more useful for your practice, fine-tuning the repetition interval, focusing on learning a difficult part of a problem, switching to a more appropriate problem, understanding every detail of the problem, and developing solution building blocks for solving other problems.

Using the correct interval length is key to making the spaced repetition process work. After each repetition, determine the most appropriate interval length for your current level of mastery for that problem.

Daily practice

LeetCode supports daily practice through the Daily LeetCoding Challenge problem, streak tracking, and other gamification mechanisms. But because the daily problem is the same for everyone, it may not be the best problem for each person given their current learning goal. If you take part in the daily challenge, use it to get exposed to new problems. But maintain your own list of model problems and practice them using your own daily schedule based on the spaced repetition process.

To get the most out of your customized daily practice process, maintain a practice journal. This journal will help you keep track of what to work on next and what specific aspects of each problem you need to focus on.

One way to think of daily practice is as the process of learning general skills using specific problems. Rather than learning about binary search in the abstract, or writing a general binary search implementation, use the specific scenarios provided in your model problems. By practicing these problems repeatedly, you will learn to associate scenarios with the algorithms and data structures you’re learning. The specific components of each scenario will act as cues that make it easier to remember how to use the algorithms and data structures when you need them for new problems.

Problem lists

Topic-wise practice, where you learn topics by solving several problems from each topic, is the best way to choose LeetCode problems during the beginning and intermediate stages of your study. You can use LeetCode’s topic tags to find appropriate problems. There are also sites like Tech Interview Handbook and NeetCode that offer curated problem lists. These offer the most useful problems from all available problems in a tag and suggest the best order in which to solve them.

Syntax and libraries

Since the model problem/solution process is based on implementing runnable solutions that you can submit to LeetCode, it requires learning the parts of a programming language that are most useful for algorithmic problem solving. This is more about depth than breadth. You only need to learn certain parts of the language, but you need to learn them well. You can divide these parts into two main categories: language syntax and language libraries.

Fine-Tuning the Learning Process

Remembering and understanding

To solve LeetCode problems, you need to know how to implement and adapt specific algorithms and data structures. But there are too many problem variations to memorize every solution. So you need to find a balance between remembering enough of the material to retrieve it quickly, while understanding it well enough that you can apply it to new problems.

Learning algorithms and data structures using the model problem/solution approach promotes a virtuous cycle. As you learn more about these topics, you get better at solving related problems. And solving problems reinforces what you’re learning.

By writing your own model solutions, you can make them memorable for you, not just for the general reader. Techniques for making your solutions memorable include explaining them in multiple ways, using diagrams, picking good identifier names, writing hints, making notes about which parts are hard to remember, using automatic logging, understanding multiple levels of abstraction, dividing your solution into chunks, and re-writing your solution as you gain experience. As you build up a library of model solutions, you can think of them as an algorithmic and data structures textbook that is customized for you.

Practice

You can’t practice for a coding interview just by doing your regular job. Although there is some overlap with regular programming work, LeetCode problem-solving practice requires a different mindset from coding real-world software or studying computer science. This mindset is encapsulated in the principles of deliberate practice.

Learn to find the solution

When you first learn a LeetCode topic, the goal is to learn the coding patterns required to solve Easy and Easy-Medium problems in that topic. But solving Medium-Hard and Hard problems requires a deeper understanding of the topic. One way to approach this after you master an implementation is to learn the steps that would be required to find the implementation, from the perspective of someone inventing an algorithm from scratch.

Solving dynamic programming (DP) problems is a good way to practice adapting a solution to each problem, since DP is an algorithmic design paradigm rather than a single algorithm. Once you know the basics of dynamic programming, learn how to identify problems that DP is good for and how to apply the DP framework. Then practice LeetCode problems that are tagged with dynamic programming.

Problem-solving

Model solutions give you a head start on similar problem types. But you should also practice using a problem-solving process that works even when you can’t directly apply a model solution. For harder problems that require more creativity, you can try techniques developed by problem-solving experts to get un-stuck.

Learning sub-problems

The fundamental unit of LeetCode practice is a single problem. But sometimes that isn’t granular enough, and it’s better to isolate the specific part of a problem that is giving you trouble. With a minor adjustment, you can also use the LeetCode platform to practice these sub-problems. A Jupyter Notebook is another useful tool for learning and documenting blocks of code that are smaller than a full solution.

Time management

One advantage of a well-designed practice process is minimizing how much time you spend on each problem. By practicing concepts and problems in the right order, you can focus on learning what you need to know rather than spending hours on a problem that you don’t have the background for. It’s good to spend as much time as necessary to understand a concept, but only once you have mastered the prerequisite concepts.

Debugging

Just as LeetCode coding differs from real-world coding, debugging your LeetCode solution differs from debugging real-world software. With LeetCode, you can assume that the official tests are valid and comprehensive. And you can limit the time you spend debugging since you always have the option to consult a working solution.

If you decide that your solution is mostly correct and just needs a few bug fixes, a few techniques can make debugging more effective. You can try rewriting a problematic section to be easier to understand, checking loop invariants to verify that variables have expected values at certain points, and writing your own minimal test cases to narrow down the problem.

Debugging a LeetCode problem requires learning how to write LeetCode test cases. When you submit your solution, the LeetCode online judge runs it on a variety of test cases designed to expose bugs. But to understand a solution, it’s best to also design your own test cases. Doing this makes you think about how your solution processes different types of data.

Advice from Learning Research

Skill transfer

One of the main challenges when learning anything is how to transfer what you learn in one context so you can apply it to a different context. This is more likely to happen when the two contexts have some overlap, when you have a fundamental understanding of what you are trying to transfer, when you use good practice techniques, and when you focus on the basics of the skills that you’re trying to transfer.

Learning plateaus

Learning a new skill is fast in the beginning, and then progress levels out. To avoid getting stuck on a learning plateau, you need to master the fundamentals, unlearn any habits that are holding you back, spend more time writing your own original solutions, and consider what you actually need to know to accomplish your goals.

The zone of optimal improvement

You will learn more efficiently if you practice problems at the right difficulty level. LeetCode offers Easy, Medium, and Hard problems. Within those categories, problems can be easier or harder depending on what problem types you have experience with. But you can also adjust any problem’s difficulty level by adjusting the time between repetitions, adjusting the number of different topics you practice together, and trying to solve a problem without looking at any reference materials.

Getting advice from books

Books can describe algorithms and data structures, but they can also provide more general advice by telling you how to avoid bad choices, giving you ideas to choose from, encourage useful patterns of thinking, acting as expert coding buddies, and occasionally giving you a critical insight that helps you in a job or an interview.

Memory

If you stop practicing LeetCode for a while, it may seem like you forget how to do that type of programming. Fortunately, these skills don’t disappear completely. Although they may get rusty, refreshing them is much less work than learning them in the first place (as long as you really learned them the first time around).

Improving through practice

Although practicing is necessary for improvement, it isn’t sufficient. If you only practice what you already know, you won’t improve. Use your practice journal to find areas for improvement that you can work on in your daily practice.

Focus on the problem

Each LeetCode problem is a test of how well you can apply the algorithms and data structures that apply to that problem. But it’s not enough just to apply a cookbook approach. Problems at the Medium level and higher contain tricky parts that can trip up a basic solution. The key is to know the algorithm well enough that you can focus on the problem and its unique challenges.

Wrapping Up

Beyond model solutions

These tips focus on the model problem/model solution approach because it’s the best way to learn the required topics. But the ultimate goal of LeetCode practice is to learn to solve problems you haven’t seen before. The way to get better at that is just to follow the standard advice: practice more problems.

Glossary

These tips use some specialized terms. You can find definitions in the glossary.

Summary

As a summary of these tips, I would give two suggestions:

  1. If you have trouble learning a concept, break it into pieces and start by learning one piece.
  2. If you have trouble remembering a concept, find a problem or part of a problem and practice that concept using spaced repetition.

(Image credit: DALL·E 3)

LeetCode Tip 50: In Case of Emergency, Read This Tip

By Duncan Smith Leave a Comment Dec 20 0

LeetCode 2023

What if you carefully implement Tips 1 through 49, and they just aren’t working? You study your model problems, but when you repeat them after a week or two, you can’t remember the relevant details. You learn a LeetCode topic in depth, but when you try to solve a new Medium problem in that topic, it seems to require different skills from the ones you learned when you were practicing relevant model problems.

In other words, LeetCode can be hard, even when you’re working on a problem labeled Medium.

Next week, I’ll review all the tips from this year. But in this last tip, let’s focus on the core of the model problem and solution system, in case you are finding that it isn’t performing as advertised.

First, it’s good to notice that something isn’t working. Although practice is the only way to improve, it doesn’t guarantee improvement. Consistent, focused practice can fail to produce results. Observing that results aren’t happening is the first step to adjusting your practice to make it work better. Tips 1-49 provide a lot of ideas about what kind of practice works best in general, but it’s up to each person to adjust their practice until it works for them.

And eventually it will work. LeetCode topics are designed to be learned. They are based on the curriculum that computer science students study before they get to the hard problems of research or industry. It’s true that most students don’t learn them to the level required to excel in a coding interview. And it may take much longer than you want to get to that point. But learning them is a step-by-step process with no magic or luck required. (Getting a job at any particular company does require some luck, but that’s the nature of coding interviews).

Let’s distill the model problem and solution process down to two elements.

Element 1: Learn a smaller concept

At its core, the system described in Tips 1-49 is based on model problems and model solutions. But a problem may be too big to learn all at once, even after you have practiced it several times. Fortunately, every problem is made up of smaller parts. To practice effectively, figure out which of those parts is giving you trouble. Suppose you’re learning binary search and it isn’t clicking when you try to use it for Medium problems. Maybe you don’t completely understand the loop condition: given how the loop is set up, why does the function always terminate, and when should you use lo <= hi vs. lo < hi. Rather than trying to understand these elements using the full binary search problem, write a smaller program that focuses only on the loop condition. Or use math and diagrams to analyze it, if that’s what makes more sense to you.

By carving up a LeetCode problem into smaller and smaller pieces, you can always reach the point where the concept you’re learning is small enough that you can completely understand it, internalize it, and remember it indefinitely. It does take time to deconstruct and learn problems this way, and it takes a different amount of time for each person depending on their innate ability and their background. But it eventually works.

Element 2: Spaced repetition

Once you find a section of a problem that’s small enough to learn, learning it comes down to spaced repetition. No matter how well you study and understand a concept, or how small that concept is, you won’t completely know it until you can reproduce it over days, weeks, and months. The spaced repetition process helps you learn things and also shows that you know them. It is compatible with the strengths and weaknesses of our brain.

This year, I’m publishing a series of tips for effective LeetCode practice. To read the tips in order, start with A Project for 2023.

LeetCode Tip 49: Glossary of Terms

By Duncan Smith Leave a Comment Dec 13 0

LeetCode 2023

A glossary of selected terms specific to LeetCode practice and algorithmic coding interviews.

accepted: The status that LeetCode reports when a submission passes all test cases and runs within the time allowance.

algorithm: The steps required to solve a problem. An algorithm operates on data stored in data structures, and can be analyzed using tools from the field of discrete mathematics. These three topics (algorithms, data structures, and discrete math) are the main areas of study required to solve LeetCode problems.

coding interview: An interview where the interviewer asks the candidate to write solutions to coding problems. The related term algorithmic coding interview specifies that the coding problems resemble those found on LeetCode, as opposed to real-world problems.

competitive programming: Solving problems as part of a contest. Although LeetCode hosts weekly and biweekly programming contests, some people distinguish between platforms like LeetCode that are explicitly focused on interview preparation, and pure competitive programming platforms like Codeforces.

daily challenge problem: A problem that LeetCode selects from their problem library and designates as the official problem to solve that day. Solving it extends your streak, adds to your LeetCoin balance, and contributes to other virtual and (possibly) real-world benefits.

deliberate practice: A method for improving performance by repeatedly focusing on specific skills that need improvement, getting feedback on results, and adjusting your practice accordingly.

Easy, Medium, and Hard: The three categories that LeetCode uses to rank problem difficulty. Easy problems can be solved with minimal specialized knowledge. Medium problems require reasonable proficiency in one or more topics. Hard problems require mastery of a topic, or combining multiple topics in creative ways.

interval: In spaced repetition practice, the elapsed time between two practice sessions for a particular model problem.

LeetCode: An online judge containing interview preparation resources, notably problems of the type asked in algorithmic coding interviews.

LeetCoin: Virtual currency that can be redeemed for digital and physical LeetCode merchandise.

model problem: A problem that is especially useful for practicing a concept using spaced repetition.

model solution: A detailed solution to a model problem that covers what you need to learn to solve that problem and related problems.

practice: The answer to the question “How do I get better at LeetCode?” Although this advice is correct in principle, executing it effectively can be challenging.

practice journal: A document where you take notes about each practice session. These notes can help you design your practice to be more effective by focusing on what is giving you trouble, rather than just endlessly solving problems.

problem: A statement of the form: given (input), return (output). LeetCode provides the input, and your program returns the output. A problem description contains a statement of the requirements, example input and output, constraints, and often diagrams.

problem list: A list of problems designed for a specific practice goal. Examples include problems that cover a specific LeetCode topic or problems that you are currently practicing using spaced repetition.

solution: The code that you write to solve a LeetCode problem.

spaced repetition: An evidence-based learning technique in which you repeatedly practice the same LeetCode problem, while increasing the elapsed between practice sessions for that problem.

solve: Write a program that is accepted by LeetCode for a particular problem. The goal is to write a complete solution for a problem you haven’t seen before within a time constraint. But other ways of solving problems are useful to get to that point.

streak: The number of consecutive days that you have submitted the daily challenge problem.

topic: A word or phrase that summarizes what skills are required to solve a LeetCode problem. A topic is usually the name of an algorithm (e.g., binary search), a data structure (e.g., hash table), a programming technique (e.g., dynamic programming), or a field of study (e.g., number theory).

This year, I’m publishing a series of tips for effective LeetCode practice. To read the tips in order, start with A Project for 2023.

LeetCode Tip 48: Beyond Model Solutions

By Duncan Smith Leave a Comment Dec 6 0

LeetCode 2023

The premise of these tips is that the best way to get better at LeetCode is to systematically learn model solutions to model problems. Just solving more problems (the problem quantity approach) or just solving problems at the right difficulty level (the problem quality approach) is not an efficient way to improve at LeetCode. Instead, you have to work through the LeetCode topics and learn the patterns for each topic. The preceding tips explain how to do that.

But there’s one skill that this process doesn’t directly address: solving problems you haven’t seen before. Given a problem in a topic that you have learned thoroughly by practicing model problems, you need to be able to solve a new problem in that topic. This is, of course, the goal of LeetCode practice. So at some point, as you’re learning a topic, you have to decide that it’s time to go beyond model problems and solutions.

Practice

Although solving model problems certainly involves practice, it’s a different type of practice from solving new problems. Solving model problems involves repeating skills in order to learn them better. To practice solving new problems, you just solve more problems. At this point, the quality plus quantity approach can work. Just solve more problems at the right difficulty level. (Solving a bunch of easy problems after you’re already good at a topic won’t make you any better at it). Quantity works at this point because you are applying skills you’re already good at. As you practice more problems, you reinforce these existing skills. And it works because most new problems will have a detail or two that you haven’t encountered in your study of model problems. As you solve more new problems, you’ll encounter more details that will round out your knowledge of a topic.

Problem-solving skills

If you try to solve a moderately difficult problem in a topic before you have learned that topic, you’re unlikely to be successful. Maybe you’ll manage to invent binary search completely from scratch. But you won’t be able to do that for every topic. So you have to learn the topics before moving on to practice.

Learning a LeetCode topic starts with learning information, like the steps of an algorithm, and learning to apply that information by solving specific problems. But at some point, you’ll have a solid grasp of how the topic works and how you can use it. Then what remains is practicing more general problem-solving skills. And although experts have come up with general principles for solving problems, there are a lot fewer of these principles than there are topic-specific principles. In fact, there’s a good argument that general problem-solving skills are really just the combination of many topic-specific skills. So while you can keep general principles in mind, you should spend most of your time on specifics.

When to start solving unknown problems

Although LeetCode has topic-focused courses that teach the fundamentals of a topic, it’s easy to get into a mode of just solving random problems using the daily challenge and the weekly contest. It requires effort and focus to go topic by topic instead. But learning a topic has diminishing returns. After you learn the basics of a topic, you should occasionally try solving a new Medium-level problem, to test your mastery of that topic. When you finish a new problem, evaluate how the process went. If you remembered all the applicable details of the topic, even if you struggled with other aspects of the problem, you may be ready to stop using model problems and solutions to learn that topic. Similarly, it’s good to spend some time practicing problems without knowing which topics apply. This is the situation you’ll be in when you’re in a coding interview, so it’s important to evaluate your performance in those circumstances.

This year, I’m publishing a series of tips for effective LeetCode practice. To read the tips in order, start with A Project for 2023.

LeetCode Tip 47: Focus on the Problem, Not the Algorithm

By Duncan Smith Leave a Comment Nov 29 0

LeetCode 2023

LeetCode works because algorithmic coding interviews focus on a limited set of topics. You don’t have to learn all of computer science, just certain algorithms and data structures, which LeetCode attempts to capture in its problem library. This list of tips recommend studying the LeetCode topics by selecting a few model problems for each topic, and learning how to solve those problems. Given enough problems for a topic, you’ll learn how that topic works in practice.

One way to prove that you know an algorithm well enough is if, when you start a new problem, you can completely focus your mind on the details of that problem without thinking about the algorithm. Since the algorithm is unchanging, you don’t want to waste any brain power rethinking it. The important thing is what a particular problem is asking.

The practical reason that you have to focus on the problem rather than the algorithm is that you can only think about what you can fit in your working memory, and working memory has a limited capacity. If you have stored the algorithm in long-term memory, you can use your full working memory for the current problem.

Another reason is confidence. If you know an algorithm well, you won’t be tempted to rush into implementation. You’ll know that when you decide to implement the solution, the details of the algorithm will come easily to mind. So you can spend as much time as you need thinking about the problem first.

As an example, consider the LeetCode problem Determine if a Cell Is Reachable at a Given Time, which was used as a Daily LeetCoding Challenge problem. The problem asks: Given an infinite grid and a start and destination cell, can you travel from the start to the destination in a specific amount of time?

LeetCode problems that require moving around grids usually involve Breadth-First or Depth-First Search solutions. So it’s tempting to start implementing one of those and see what happens. Without giving away too much, let’s just say that there are reasons these algorithms don’t apply in this case. But to reach that conclusion efficiently, you have to think first and code later.

This year, I’m publishing a series of tips for effective LeetCode practice. To read the tips in order, start with A Project for 2023.

LeetCode Tip 46: Are You Improving?

By Duncan Smith Leave a Comment Nov 22 0

LeetCode 2023

LeetCode encourages you to develop a daily LeetCode habit. Every day, they identify one of their problems as the Daily LeetCoding Challenge problem. If you solve that problem, you extend your daily streak. If you don’t, your streak resets to zero. This gives you a reason to open the site every day and solve the daily problem.

But while it’s possible to learn something by following this daily habit, you won’t keep getting better forever. Eventually, a daily habit will only maintain your current skill level. To improve further, you need a different approach.

To learn more about the ideas in this tip, see Which Works Better: Habits or Projects? by Scott Young.*

Regular practice is necessary for improvement, but it isn’t sufficient. The path of least resistance in daily practice is to repeat skills that you already know. This type of practice isn’t useless. You’ll at least avoid losing those skills. But you won’t get any better.

To improve your skills rather than just maintaining them, you first have to find a strategic area to improve. Your practice journal should have some suggestions. Find a problem you have practiced before and check your most recent notes. Unless you have mastered the problem, your practice notes should identify a part of the problem that you had trouble with. If you work on something that you found difficult in your last repetition, then you have a chance of improving.

Improvement requires more effort and attention than just practicing every day. You have to analyze your performance and figure out what gave you trouble. And it isn’t always obvious what to work on. For example, let’s say you practice a problem that requires binary search and you correctly identify binary search as an appropriate algorithm, but you can’t figure out how to use binary search for this specific problem. You know how to implement binary search, so that’s not what you need to work on. You know enough about what a binary search problem looks like that you selected the right algorithm. But something about the application of binary search still eludes you. You have to figure out what that is, so you can learn and practice it. This analysis takes time, but it’s necessary.

Sometimes a daily habit can block improvement. If you implement an algorithm many times over many days and weeks, you’ll eventually stop thinking about the individual steps. It will be so easy that your fingers will just implement it on their own. This is useful for easier problems. It lets you finish those problems quickly. But harder problems may require you to modify the algorithm in subtle ways. Rather than thinking of the algorithm as a black box, you’ll have to take it apart and look at each step, the way you did when you were first learning it. You may have to unlearn habits if they are preventing you from understanding the algorithm well enough to apply it to hard problems.

If you’re practicing LeetCode regularly, take some time once in a while to ask yourself if you’re improving, or just practicing.

This year, I’m publishing a series of tips for effective LeetCode practice. To read the tips in order, start with A Project for 2023.

LeetCode Tip 45: Forgetting and Remembering

By Duncan Smith Leave a Comment Nov 15 0

LeetCode 2023

Solving LeetCode problems is a specialized type of programming. Just as some programmers like to work on low-level code for embedded systems, and others are experts in web applications, programmers may choose to learn interview programming using LeetCode.

But while programmers use their real-world specialty every workday, they might go years between job interviews. So if you’re going to invest more than a little time in LeetCode practice, it’s worth thinking about how best to retain your hard-won interviewing skills during the time between interviews.

To learn more about the ideas in this tip, see No, You Haven’t Forgotten Everything by Scott Young.

Here’s the canonical LeetCode interview preparation process:

  • Step 1: Decide that it’s time to look for a job.
  • Step 2: Grind on LeetCode for a few weeks/months.
  • Step 3: Interview with multiple companies. Get multiple offers. Make them fight each other.
  • Step 4: Profit

During the time that you’re preparing for interviews, there’s an immediate benefit to carving out time in your schedule for LeetCode practice. But once you accept an offer, you have other priorities. Rather than proving your value in an interview, you’ll be proving your value by ramping up on your new job. So how do you avoid losing all your LeetCode skills while you’re busy doing real-world programming?

To answer that question, it helps to understand why we forget things. The obvious answer is disuse. The more time that goes by since you last implemented Dijkstra’s Algorithm, the more likely it is that you’ll forget some details.

But there’s also a less obvious explanation for forgetting: interference. According to the theory of interference, we never truly forget anything. Some memories are just more difficult to recall. As an analogy, imagine that there’s a web page that has some information you’re looking for, but you’re having trouble finding the search query that returns it.

Interference is problematic because it prevents you from remembering something that you need. But it’s also useful because it focuses your brain on the memories that are most relevant to your current needs. For example, if you’re working on a real-world programming task, you might not want to remember every LeetCode pattern you have learned. But in an interview, you would like to have access to those memories.

To recall the right memories at the right time, you can take advantage of the brain’s system for bringing less used memories back into active use. As explained in LeetCode Tip 43: Find the Zone of Optimal Improvement, the brain maintains a retrieval strength for each memory, which it increases when a memory is useful but difficult to retrieve.

This system is the key to maintaining your LeetCode investment. If you learn a topic thoroughly the first time around (e.g., by using the process outlined in these tips), you can be confident that it will be stored in your long-term memory. So when it’s time to prepare for another interview, you can wake up these hard-to-recall memories, rather than learning topics from scratch. Then, when it’s time to go back to full-time job mode, you can let those memories go dormant again.

This year, I’m publishing a series of tips for effective LeetCode practice. To read the tips in order, start with A Project for 2023.

LeetCode Tip 44: Taking Advice

By Duncan Smith Leave a Comment Nov 8 0

LeetCode 2023

Ask any experienced LeetCoder what you should do to improve, and they’ll give you the same answer: practice. These tips also focus on practice, and for good reason. If you want to learn to solve LeetCode problems, there’s no substitute for practice. And it’s challenging to practice consistently, so regular reminders can be helpful. But you can’t just practice.

In Most Books Won’t Change Your Life (But You Should Read Them Anyway), Scott Young considers the value of “advice books,” defined broadly as any book that might convince you to change something in your life. As anyone who has tried to implement advice can attest, it’s a lot easier to read advice than it is to make a change. So the question is: should we only read an advice book if we have time to try out what it recommends?

Translating this question to the world of LeetCode practice: Should you only read a book or article if it applies directly to your current practice topic? For example, if you’re learning binary search, should you only read the binary search section in an algorithms textbook, or maybe something about loops and arrays?

The idea of mapping your reading list to your practice schedule seems reasonable. Technical material is hard to read and understand. Pairing it with a hands-on problem-solving is a standard way to make learning more effective.

But Scott, using the economics concepts of marginal costs and marginal benefits, argues that it’s worth reading more than just what you can directly use. In this calculation, marginal costs are the costs of buying and reading books. For example, a typical nonfiction book (not a textbook) might cost $20 and require 20 hours to read. If the marginal benefit you get from reading it is more than $20 plus the value of 20 hours of your time, you come out ahead.

To help calculate the marginal benefit of reading, here are some ways that reading can help with coding practice, beyond just showing you how to solve a problem:

  • Avoid bad choices: A book can warn against bad architecture, design, or practice choices, so you know to avoid them.

  • Build your idea list: When you’re ready to implement a new idea, like a problem-solving strategy or an algorithm, you can only pick from the ones you know about. When you read about an idea, you can add it to your list. If you regularly add to your list, and bubble better ideas to the top, you’ll always have good ideas to choose from.

  • Create patterns of thinking: Some ideas are more about a general approach than a specific procedure. For example, the idea of keeping a practice journal can help you become more intentional about your learning. Once you know about that idea, you can implement it as you work on other things. It’s not the type of idea that you have to carve out time to practice on its own.

  • Find coding buddies: If you work or study with experienced people, some of it will rub off on you. Reading books lets you learn from a wide range of experts, even if you don’t work with them directly.

  • Win the coding lottery: Beyond the reliable benefits of reading, there is the element of luck. It’s always possible that you could read something in a book that helps you pass an interview or solve a difficult problem at work. The potential benefit of such an event could more than make up for what you invest in your reading habit.

This year, I’m publishing a series of tips for effective LeetCode practice. To read the tips in order, start with A Project for 2023.

LeetCode Tip 43: Find the Zone of Optimal Improvement

By Duncan Smith Leave a Comment Nov 1 0

LeetCode 2023

To practice LeetCode effectively, you have to choose the correct problem difficulty. If you start with Hard problems when you’re first learning a topic, you won’t learn much because you won’t be able to make much progress on the solution, so you won’t get a chance to practice the topic. At the other extreme, if you practice Easy problems when you already know a topic well, you won’t learn much because you won’t challenge yourself.

But problem difficulty is not the only way to adjust the difficulty of your practice. You can also use other aspects of your practice routine to find the optimal difficulty level.

To learn more about the ideas in this tip, see Desirable Difficulties: When Harder is Better for Learning by Scott Young.

Desirable difficulty is the idea that making learning harder can make your study process more effective. For example, switching from Easy to Medium problems for a topic that you have some experience with will make it more difficult to solve each problem. But the additional challenge provided by Medium problems will push you to learn more about each topic than you would by solving Easy problems.

Techniques

Once you select a problem with the correct difficulty level, you can further find-tune the level of practice difficulty using these techniques:

Spacing

If you practice a problem until you solve it, then delete your code and immediately write it again from scratch, it will be easier to solve the second time. Since your first attempt was just a few minutes earlier, you’ll easily recall some details. If instead you wait a week to make your second attempt, you’ll find it more difficult to come up with the solution. But in the long run, you’ll make more progress if you space out your practice. This is the idea behind spaced repetition.

Variability

If you practice a sequence of binary search problems at a similar difficulty level, the problems will get easier over time. Each problem will give you more experience with binary search, and you’ll be able to concentrate on the solution patterns required for binary search, with no distractions from other problem types. If instead you alternate between binary search problems and binary search tree problems, it will make your practice more difficult. When you solve a binary search tree problem, you’ll displace a bit of what you remember from binary search, and vice versa. It will take longer to become proficient at both topics than it would if you learned them sequentially. But in the long run, interleaving topics will help you gain a stronger mastery of each topic.

Testing

Reading someone else’s solution is much less effective for learning a topic than solving a problem on your own, even if you are reproducing a model solution. The process of implementing a solution gives you experience that you can’t get just by studying code. This is known as the testing effect.

Research

Although research supports the effectiveness of spacing, variability, and testing, there isn’t a consensus about why these techniques work. One theory is that the brain maintains a retrieval strength for each memory. You can recall memories (like how to implement binary search) more easily when the connection to that memory is stronger. The brain strengthens the connection when it detects that a stronger connection is needed. If you retrieve a memory easily because you used it recently to solve a problem (low spacing), because you have been practicing similar problems (low variability), or because you are just reading the solution (no testing), your brain concludes that the connection strength is fine. On the other hand, if you have to struggle to recall a key concept but you eventually retrieve it, that’s a signal that the concept is important, so the brain strengthens the connection.

There’s another theory explaining why variability is useful for learning. When you interleave similar problems, your brain has to distinguish between them. For example, consider binary search problems and binary search tree problems. In both cases, you need to find a target element by moving left or right in an ordered data structure, eliminating half the search space on each iteration. But for binary search, you’re using an array, so you can jump to any location in constant time, while for the BST, you are traversing tree nodes one at a time as you search for the target node. Solving a binary search tree problem after having recent experience with binary search forces you to think more carefully about which techniques to apply at each point in the algorithm, and which algorithm is most useful for the problem.

This year, I’m publishing a series of tips for effective LeetCode practice. To read the tips in order, start with A Project for 2023.

LeetCode Tip 42: Getting Past a Learning Plateau

By Duncan Smith Leave a Comment Oct 25 0

LeetCode 2023

When you first start using LeetCode, progress can be rapid. If you have programming experience but no LeetCode experience, you can get a general idea about this type of programming by solving a few easy problems. Similarly, when you first learn about a topic like binary search, it might only take a few hours before you can solve straightforward problems on your own. But then progress gets slower. Medium problems are trickier and take longer to master. To solve problems at that level, you have to understand the target algorithm well enough to customize it for each problem. And Hard problems generally require an algorithmic or mathematical insight that won’t come to mind until you have significant practice under your belt. So you may find that even after a lot of practice at this level, solving problems doesn’t seem to get any easier. A learning plateau is a point where continued practice doesn’t seem to improve results.

To learn more about the ideas in this tip, see The Intermediate Plateau: What Causes It? How Can We Move Beyond It? by Scott Young.

Here are three potential causes of a LeetCode learning plateau, and how to address them.

Harder problems require exponentially more expertise

Let’s say you spend a day studying a LeetCode topic and find that you can solve most Easy questions in that topic. Spending one more day won’t get you comfortable at the Medium level. It might take a week or a month, depending on your background. And Hard problems might require multiple months, as you study several related topics and integrate them to solve those trickier challenges.

The straightforward way to build exponentially more expertise is to spend exponentially more time studying. But you also have to consider your goals. Maybe you don’t need to master Hard problems, since they are less common in real interviews. You could instead optimize for breadth of knowledge, with the goal of mastering many topics at the Medium level. This will prepare you to handle the common question types that you might encounter in an interview.

Harder problems require a different kind of thinking

The easier a problem is, the more likely it is that you can solve it by applying a pattern. As you practice, you learn different ways to solve problems. When you encounter a new problem at the Easy or Medium level, apply a pattern you know, make a few adjustments, and solve it in 30-45 minutes.

If you try this approach with Hard problems, it’s not as likely to work. You might complete a solution that works for some test cases, but find that other cases are out of reach. Your solution likely won’t be efficient enough for large cases. Or it won’t be general enough, so you’ll need to add special cases for specific tests.

To resolve this dilemma, get back to basics. Return to topics that you already know, and study them again with the benefit of experience. Make sure you really understand why every part of an algorithm works, not just how to implement it. Study the mathematical models behind the algorithm. You may need to unlearn some techniques that you relied on to solve Easy and Medium problems, and learn to solve Hard problem using more foundational methods.

Solving harder problems requires more original thinking

Learning model solutions for model problems gives you basic patterns. To write a new model solution, you’ll start with someone else’s solution and modify it so it fits your style. Then you can practice and learn it so you can apply it to new problems. It will become part of your repertoire, and if you practice it on enough problems, you may barely need to think about it. But it nevertheless started out as someone else’s solution.

Since every problem on LeetCode has one or more posted solutions, you can take the same approach with Hard problems. Look through the solutions, find a good one, and turn it into a model solution. But this is less useful for Hard problems, since aren’t as similar to each other. Once you get to the plateau of Easy and Medium problem mastery, you have to spend more time inventing your own solutions using the experience you have so far.

This year, I’m publishing a series of tips for effective LeetCode practice. To read the tips in order, start with A Project for 2023.

  • « Previous Page
  • 1
  • 2
  • 3
  • 4
  • 5
  • …
  • 49
  • Next Page »

Stay in the Know

I'm trying out the latest learning techniques on software development concepts, and writing about what works best. Sound interesting? Subscribe to my free newsletter to keep up to date. Learn More
Unsubscribing is easy, and I'll keep your email address private.

Getting Started

Are you new here? Check out my review posts for a tour of the archives:

  • 2023 in Review: 50 LeetCode Tips
  • 2022 in Review: Content Bots
  • 2021 in Review: Thoughts on Solving Programming Puzzles
  • Lessons from the 2020 LeetCode Monthly Challenges
  • 2019 in Review
  • Competitive Programming Frequently Asked Questions: 2018 In Review
  • What I Learned Working On Time Tortoise in 2017
  • 2016 in Review
  • 2015 in Review
  • 2015 Summer Review

Archives

Recent Posts

  • Do Coding Bots Mean the End of Coding Interviews? December 31, 2024
  • Another Project for 2024 May 8, 2024
  • Dynamic Programming Wrap-Up May 1, 2024
  • LeetCode 91: Decode Ways April 24, 2024
  • LeetCode 70: Climbing Stairs April 17, 2024
  • LeetCode 221: Maximal Square April 10, 2024
  • Using Dynamic Programming for Maximum Product Subarray April 3, 2024
  • LeetCode 62: Unique Paths March 27, 2024
  • LeetCode 416: Partition Equal Subset Sum March 20, 2024
  • LeetCode 1143: Longest Common Subsequence March 13, 2024
Red-Green-Code
  • Home
  • About
  • Contact
  • Project 462
  • CP FAQ
  • Newsletter
Copyright © 2025 Duncan Smith