The theory of deliberate practice is a popular starting point for online article writers. I subscribed to an alert for the term, and I generally get a few results every day (of varying quality). Its popularity isn’t surprising. Deliberate practice offers a process that anyone can use to get better, assuming they are willing to follow it carefully and put in the required hours. Articles and books on the topic often provide examples of well-known experts who followed a deliberate practice process. Geoff Colvin’s Talent is Overrated mentions Tiger Woods pushing golf balls into the sand to make them harder to hit. James Clear writes about Kobe Bryant’s 800 jump shots before practice. But there are also examples of people who didn’t have coaches to steer them towards the right practice steps, but nevertheless achieved incredible results. I recently finished reading Masters of Doom, the story of the founders of id software. One of the recurring themes in the book is the incredible work ethic of John Carmack, co-founder, graphics engine developer, and all-around game programming legend.
This post is part of a series of commentaries covering each chapter of Competitive Programming 3 by Steven and Felix Halim. You can find the rest of the posts in the series by visiting my CP3 post category.
Many of the problems in the UVa Online Judge are taken directly from past ACM-ICPC contest problems. If you’re preparing for this contest or the IOI (which targets a subset of ICPC content), it makes sense to be familiar with these problems. But even if you’re planning to compete on platforms like TopCoder and CodeForces, it can be useful to train using UVa OJ problems, despite the platform’s quirks. Competitive programming problems tend to cover similar topics regardless of the contest platform, especially when it comes to easy and medium problems. The difference is mainly about which topics are emphasized more.
Because UVa OJ has been around for a while, several books use its problems as exercises. One of these is Competitive Programming 3 (CP3), the companion book to the uHunt site. Last week I wrote about the Chapter 1 uHunt starred problems. This week I’m going to cover some highlights from the corresponding chapter in the CP3 book. I’m using the 3rd edition, but you can find similar (but older) content in the free 1st edition ebook.
This post is part of a series that considers what can be learned from the problems in each chapter of uHunt, a tool for competitive programming practice. You can find the rest of the posts in the series by visiting my uHunt post category.
The problems in uHunt Chapter 1 are introductory and ad-hoc problems. They help uHunt users get familiar with the UVa Online Judge system, and they don’t require any specific competitive programming techniques to solve. Nevertheless, there were quite a few challenging problems in this chapter.
How to Attack a Programming Puzzle contains six tips for using UVa OJ. This post contains my remaining thoughts on solving the types of problems found in Chapter 1.
When you’re working on a serious learning project, especially if you’re applying deliberate practice techniques, it’s essential to have a set of core habits that you can rely on. Deliberate practice is intended to be a demanding process (see elements #4 and #5 from the linked post). This is good because it makes you push against your limits, but it can also make it difficult to maintain a schedule if you’re just using an ad-hoc process. Experimenting with habits and selecting a few that work for you makes it more likely that you’ll be able to continue working on your project for as long as it takes to complete it.
A productivity habit is something you do on a regular basis (often daily) to help you be more productive. Although the habit may have some value on its own, what’s more important is the effect it has on your work. For example, I find it useful to keep track of how long it takes to complete various tasks. Analyzing this data over time can uncover some interesting trends. But it’s even more powerful to use time tracking for setting time goals, like the number of hours per day that I commit to spending on a project.
Here are the habits that I have found to be the most useful as I work on Project 462.
Do these questions sound familiar?
What are the important problems of your field?
What important problems are you working on?
If what you are doing is not important, and if you don’t think it is going to lead to something important, why are you … working on it?
They come from a 1986 speech by mathematician and Turing award winner Richard Hamming. Hamming originally asked them in the dining hall at Bell Labs, but they have since inspired other people who are interested in finding the best way to spend their work hours.
When people hear the term competitive programming, they naturally think about programming contests and rankings. People who are encountering the term for the first time are just using the literal meaning, while those who are familiar with the topic think about the top competitors that they hear a lot about. But someone who is just starting to learn to solve the types of problems found in programming competitions may see things differently. In my experience, introductory problems often challenge mathematical thinking skills more than programming skills. Only a small subset of a programming language is required to solve these problems, and there’s plenty of time to look up syntax (since beginners are often not taking part in a timed competition). However, most problems (other than the very easiest ones) are structured to require mathematical thinking.
Despite the increasing availability of alternative options such as online learning sites and coding boot camps, many students who are interested in programming still pick the traditional approach: getting a Computer Science degree. If you plan to do academic research, a degree is really the only option. But for someone who wants to get a job as a programmer, there are both advantages and disadvantages to a traditional degree.
When you start solving programming puzzles like those on uHunt Chapter 1, what are you learning about? The obvious answer is that you’re learning about competitive programming. After all, uHunt has a companion textbook called Competitive Programming, and many programming puzzle sites are associated with the competitive programming community, or even run their own contests. But I don’t think that’s the right way to look at it. First of all, there’s not much competition happening when you’re first getting started. You may be using a site where the only rating is the number of problems submitted. Or if you are participating in real-time contests, you may not be making it through many problems before time runs out.
If you want to get better at programming, you need to get better at algorithms. In some ways, that statement is tautological. To quote Computer Science pioneer Niklaus Wirth, Algorithms + Data Structures = Programs. But besides the algorithms that you write yourself, it’s also worth studying well-known algorithms such as those taught in introductory Computer Science classes. Some software developers object to that idea. They say their language or framework already provides all of the standard algorithms, or that they can easily find them on the Web. Why do they need to learn how they’re implemented? It’s certainly true that professional software engineers shouldn’t re-implement standard algorithms for the purpose of using them in a product. But that’s not the point of learning them. The reason they’re part of CS education is that they contain useful ideas. Here’s one example: In modern programming languages, you don’t have to worry about finding the end of a string. The language hides that aspect of string implementation. But by studying string manipulation algorithms in C, you find out about the idea of a sentinel value. This is helpful in understanding how leaf nodes are represented in a tree. And now you have a couple of examples of a concept you can use in other situations where you need to indicate the end of a section of data.
If you want to get a lot better at a skill, you need a process for practicing it. When you follow a process, it encourages you to practice in a consistent way, rather than using whatever practice technique you happen to feel like using on a given day. As you get experience using your process, you can look for ways to improve it. In fact, improving your process should be a step in your process, since improvements makes your practice more effective every time you use the process. In this way, you can set up a virtuous cycle where your practice helps you improve your process, which in turn improves your practice. Here on Red-Green-Code, I’m working on a process for getting better at programming.