When you write a LeetCode solution, it may have bugs. This is one way in which LeetCode programming and real-world programming are similar. But debugging your LeetCode solution doesn’t always work the same way as debugging your real-world code.
In the real world, when someone gives you a task, you’re the one person responsible for completing it. If you get stuck, you can ask your teammates or your AI buddy for help. And other developers may need to review your code before it is accepted into the product. But you are ultimately responsible for it. So when your code has a bug, it’s up to you to diagnose and fix it. It’s also up to you to decide when your code is “done” and ready to submit for review. And you are the one person writing that code for your particular product.
On LeetCode, thousands of people solve each problem, tens of people publish their solution, and one person writes an official editorial. So when you’re debugging your code, you always have the option of checking other solutions to see if you’re on the right track. And unlike real-world advice, which may not apply directly to the problem you’re trying to solve, these other solutions will be highly relevant, since they apply directly to the problem you’re working on.
This means it’s important to ask yourself at each point in the debugging process whether debugging is the best thing you could be doing with your time. If your solution is mostly correct but has a few bugs, it may be worth spending some time debugging, so you have a solution that you wrote yourself from beginning to end. But if your research tells you that your solution is unlikely to work, it’s probably better to cut your losses rather than trying to debug it into submission. Accept that you went off in the wrong direction, and learn a better way to solve the problem.
Another way that LeetCode programming differs from real-world programming is the testing process. In the real world, developers may write unit tests. But these tests, as they are written by the same person who is writing the real-world code, are often imperfect. They may not cover every important use case, or they may succeed when they should fail or fail when they should succeed.
On LeetCode, you can assume that the tests are reliable. LeetCode problems are easier to test than real-world software, since they are well-defined and constrained problems. Test cases are written and reviewed by experts, then reviewed again by LeetCoders as they try out the problems and propose new test data. So unless the problem you’re solving is very new, running your solution against the official tests cases will subject it to a rigorous test process. If your solution passes, you can conclude that it does a good job of solving the problem as specified.
But there are a few things to consider as you use official LeetCode test cases to evaluate your solution. First, unlike with Test-Driven Development (TDD) in the real world, it’s not a good idea to use LeetCode tests to drive the development of your solution. According to the TDD approach, you would run the official tests before you write any code, then write code to make the tests pass. But this isn’t what LeetCode tests are designed for. They are written to test a complete solution, not a single function. Furthermore, if you’re just trying to get tests to pass, you may end up with a solution that works for the small early tests but is not efficient enough to process larger tests fast enough.
So rather than letting tests drive your development, consider from the beginning what data you will need to handle. The “Constraints” section of the problem description will give you this information. This is also how an algorithmic coding interview works. Your interviewer will want you to provide a conceptual design for your solution. You won’t have time to build it iteratively, guided by test cases. (If you get a real-world coding problem in your interview, this advice may not apply. In that case, ask whether you should write unit tests first or at all).
Even if you complete your solution before running it against any test cases, you may still encounter a debugging snag. LeetCode will helpfully tell you that your solution failed on test 31 out of 100, which means it passed the first 30 test cases. It will even give you the test data and expected output, and let you copy the test case to your local tests. That lets you modify your solution and run it as many times as you want until it passes test #31. Once your fix is done, you can submit your solution again. Maybe this time it will fail on test #73. Repeat the process and submit again. Sometimes you’ll have to do this a few times as you discover more bugs in your solution. But make sure you aren’t just adjusting your implementation specifically for these failed tests. Ideally, you want an elegant solution that solves the general problem and avoids special cases. LeetCode test cases are designed to check for particular classes of bugs in your solution. But you want your solution to work on any valid test data because your algorithm is correct, not because you designed it to work on particular test data. So if you get more than one or two failed tests cases, consider going back to your design to see if it needs an update.
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.