Over the past couple of weeks, I have been writing about deliberate practice as described in Peak by Anders Ericsson and Robert Pool. The book describes three types of practice: Naïve practice, purposeful practice, and deliberate practice. The latter two types of practice are both effective, but there’s a key difference that makes deliberate practice the best choice. The difference is where your training plan comes from. Purposeful practice can be used with any reasonable plan. Deliberate practice requires that you practice using a plan that has been proven to work by an expert who has gone before you and achieved success in your target field.
How might we find an expert training plan for competitive programming? This type of programming is different from regular software development. So it won’t do to use a standard programming training plan, as provided by a university curriculum or a programming boot camp. Competitive programming is taught as a specialty in some universities, where coaches devise their own training plans to build winning teams each year. But that’s only useful if you’re a student at one of those universities. There are a couple of books specifically about competitive programming, including Competitive Programming 3, which I’m in the process of writing a chapter-by-chapter summary for.
But for today’s purposes, I’m going to cover training advice provided by competitive programming experts on Quora, specifically in answers to the question What is the best strategy to improve my skills in competitive programming in 2-3 months? Over time, that question has become a merge target for a number of similar questions, and quite a few experienced competitive programmers have weighed in with suggestions.
Training Advice
Every competitive programming training system revolves around solving contest problems. But just solving problems is an example of naïve practice. It may have some benefits, but it’s far from the most effective approach. An effective training method also relies on other activities that support your problem-solving practice: finding and preparing to solve problems, thinking about how you’re solving a problem as you’re solving it, and following up after you finish solving the problem.
Here are some things to consider as you create your ideal deliberate practice training plan.
Picking an online judge
Competitive programming problems usually come from online judges, but not every online judge is equally useful at every stage in your practice. Sachin Gupta from HackerEarth suggests looking for an online judge that satisfies these three requirements:
- Offers high-quality problems
- Lets you see other people’s solutions
- Categorizes problems by topic
One way to find high-quality problems is to find judges that are currently running contests that attract top competitive programmers. Since multiple sites run contests, a good assumption is that top talent wouldn’t be participating if the problems didn’t meet their quality bar. Topcoder and Codeforces are examples of online judges that attract well-known contestants.
But those three characteristics of an online judge aren’t completely black and white. For example, consider UVa Online Judge. It includes many old problems whose quality isn’t up to modern standards, it doesn’t support viewing other people’s submissions, and it provides very little information to help debug failed submissions. However, it offers very fine-grained problem categorization through uHunt and debugging through uDebug. And an advantage of having older problems is that solutions are easy to find on GitHub and programmer blogs. So I find that it works for my current goals.
Choosing practice problems
Once you have an online judge, you need a strategy for selecting problems, since there are too many to solve all of them. A common piece of advice is to find a problem set that lets you sort in descending by the number of people who have solved each problem, and start with the first (easiest) one. Codeforces problems can be sorted that way.
An advantage of this approach is that it helps you find your current skill level. You can then make sure that you’re solving problems slightly above that level, rather than wasting your time on problems that are too easy or too hard.
A disadvantage is that while the problem difficulty may be predictable, the problem topics will be random unless you add other criteria to your problem search. It’s a bit like taking a textbook where problems are arranged by difficulty, and solving problem #10 in each chapter. You probably wouldn’t get enough practice with each topic, unless you were already familiar with the subject matter.
So I prefer the approach of sorting problems by topic rather than by difficulty. In my experience, the uHunt starred problems provide the right variety of easy problems to get familiar with a topic, and harder problems for more of a challenge. Once I have covered all of the standard topics in the CP3 book, the “sort by difficulty” approach may become more useful.
Finding simple solutions
Contest problems are designed to be solved quickly, so the solutions must be simple. That doesn’t mean the problems are easy to solve, but the solution code should be straightforward and relatively short, especially for beginning and intermediate problems.
If you have an accepted solution that is not simple, it’s worth reading editorials and solutions to see if there’s a simple solution that you missed, so you can use it next time you have to solve a similar problem.
Bohdan Pryshchenko, a red coder on Topcoder and Codeforces, has some interesting advice about using editorials and solutions:
- Pick practice problems based on the quality of their solutions and editorials. Don’t pick the problem first and then hope that you’ll find good resources after you solve it (or when you get stuck).
- Don’t just read one solution. Find solutions that will teach you different things. For example, one solution may have the fastest runtime. Another may have the shortest source code. Once you know the correct solution, it’s even worth studying incorrect solutions (ones that the online judge didn’t accept), to see what mistakes people made.
Isolating sub-skills
Solving a competitive programming problem requires combining a number of skills. You have to read and understand a problem statement, formulate a logical solution, implement that solution in a programming language, and think of test cases to exercise your implementation. You may be stronger in some of these areas and weaker in others. For example, some people are expert coders, but do poorly in technical interviewers because they aren’t familiar with solving programming puzzles.
Jayesh Chaudhary has some suggestions for separating problem-solving practice from implementation practice:
- To isolate problem-solving practice, read the problem statement and formulate a solution, but don’t implement it. Just consult the editorial to determine if your solution is correct.
- To isolate implementation practice, read the problem and check the editorial for the overall solution. Then provide your own implementation and submit it.
One of the characteristics that distinguishes purposeful practice from naïve practice is isolating part of a skill so it can be targeted independently. For example, serious music students repeatedly practice just the parts of a piece that they find difficult. They don’t play the entire piece over and over. Similarly, serious golf students practice isolated parts of the game, like putting, rather than just playing entire games. Programming puzzle practice can similarly be broken down.
Don’t Just Practice
Viktória Nemkin writes:
It’s one thing that you know how to solve stuff in theory. It’s a completely different thing that you can code it, it compiles and runs, gives no errors, you made sure all variables are big enough so they will fit, it is fast enough and doesn’t use too much memory.
If you want to get good at competitive programming, then you have to solve a lot of problems from beginning to end, including implementing solutions and submitting them to an online judge. There’s no substitute for getting your hands dirty with real code.
But if you just jump in and start submitting solutions, you won’t be making the best use of your time. It’s also important to think about the source of your practice problems, what order you’re solving them in, whether your solutions are as simple as they could be, and what parts of the problem-solving process are holding you back.
(Image credit: Christy)