You can’t debug a LeetCode solution without studying test cases, the textual input that every LeetCode program is required to process. The LeetCode platform verifies that every test case, whether an official test case or one you invent, meets the formatting and range specifications from the problem statement. The platform also gives you the correct output for every input. This platform behavior ensures that LeetCode test cases are reliable. Both the input and output are guaranteed to be correct.
But these platform guarantees don’t mean you can just ignore the test cases. Although you can rely on the correctness of the test cases and test results, understanding a model solution requires understanding the inputs and outputs, and a good model solution should explain the algorithm using specific test case examples.
The simplest way to use test cases is just to take what LeetCode gives you. First, make sure your program passes the sample cases. Then submit it, review the official test case results, and fix any bugs. This approach gets the job done, but it means you’re relying on someone else to design good test data, and only reviewing that data if it exposes bugs in your implementation.
To get more involved in test case production, use the random data approach: Write a short program that generates random numbers, letters, tree nodes, or whatever input the program requires. Paste that data into the LeetCode interface, run your program, and see what happens. This approach encourages you to think about the input. The amount of thinking required depends on the input criteria. For many LeetCode problems, random numbers in the appropriate range, or random lowercase letters from a to z, are good enough. Some problems require a more sophisticated test case generator. For example, if you have to generate a binary search tree, your generator has to understand BST node ordering rules. But spending time on your input generator is time well spent. To generate input, you have to understand the input requirements, which gives you a head start on your design.
Although a random test case generator lets you verify your program with as much input data as you want, you may not have enough time to generate all important inputs. If a program takes integers from $0$ to $2^{31}-1$ as input, you would have to generate a lot of data to have even a 10% chance of producing and testing both $0$ and $2^{31}-1$. (How long that would take is left as an exercise for the reader). So when you generate random data, it’s best to combine it with some hand-crafted test cases to make sure you cover all the input that might cause trouble for your program, like the extreme values in the input range.
Algorithms often perform differently on different inputs, which is why computer scientists study the best-case, worst-case, and average time complexity of algorithms. For example, a naïve QuickSort implementation can take $O(n^2)$ time to sort input that is already sorted! This is another reason to understand your input data. If you generate random data to test your QuickSort implementation, it’s unlikely that you’ll get sorted data. So you have to think about what data will best exercise your algorithm.
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.