Thinking Competitively
Here’s an exchange that took place last month on Reddit (r/learnprogramming):
Question: Where and how to learn ONLY for competitive programming?
Answer 1: Competitive programming without learning regular programming….good luck with that.
Answer 2: You need to to crawl first before you can even begin to think competitively.
Answer 3: Learn to program first before even thinking about competing.
We can debate the wisdom of the original question, which asks about learning to program just to get good at competitive programming. Nevertheless, the answers reflect a misguided (though common) assumption about competitive programming: that it’s only for programming experts with huge brains frantically typing for 5 hours. Instead, what if we approached competitive programming as a way for beginners to learn to program from scratch? That’s the premise of Daniel Zingaro’s new book, Learn to Code by Solving Problems: A Python Programming Primer.
Programming in Python
Dr. Zingaro’s previous book, Algorithmic Thinking: A Problem-Based Introduction, took a similar approach: He used problems from programming competitions to teach algorithms. But while that book used the C programming language and jumped right in to hash tables in Chapter 1, the new book assumes no previous programming experience, explains solutions in Python, and spends the first four chapters on basic topics like loops and conditionals. Dictionaries (the Python implementation of hash tables) show up late in the book, in Chapter 8.
If you already have some programming experience, you might wonder what this book offers you. While giving it as a gift to the prospective programmer in your life is always an option, you might also find it useful as an introduction to Python, if you mainly program in another language. I don’t use Python much, so I found the chapters on lists, sets, and dictionaries to be useful reminders on how those data structures work in Python (compared to C# and TypeScript, my primary languages). And while the main language that people associate with competitive programming is C++, Python is friendlier for people who are using contest problems to get better at problem-solving or coding fluency. Python is also convenient when you’re writing interview code on a whiteboard. Its readable style makes it easier to explain what you’re doing to the interviewer, and the code tends to be shorter than the equivalent C++ or Java.
The Online Judge Verdict
If you’re on board with the benefits of Python, there are already plenty of books you could use to learn it, some for beginners and others for more experienced programmers. The key feature of this book is the focus on public online judge problems. While programming book authors like to use original problems or sample applications to explain language features, that’s not always the best approach for learning a programming language. Sample applications (e.g., building a simple e-commerce website) have the advantage of presenting a language in a realistic context. But this approach tempts the reader to simply follow along with a step-by-step process, which isn’t the best way to learn. As for standalone programming problems, they can be helpful for testing whether you really understand the contents of a book chapter. But writing high-quality programming problems is hard. And even if the author is kind enough to provide an answer key at the back of the book or on a companion website, that still only gives you one person’s implementation of the solution.
So problems are a good feature of a programming book, but they can be hard for the author to get right. In contrast, using contest problems in a programming book has several advantages. The authors of contest problems know what makes a good problem, since they see their problems being tested by a discerning group: competitive programmers. If the problem had bugs when the problem setter wrote it, someone probably already found them before the problem made it into a major contest. Or even if a bug made it into the contest, a book author can just skip that contest and use another one.
One common complaint about contest problems is that the problem statement can be hard to understand. Dr. Zingaro avoids that concern by rewriting the problem descriptions in a consistent style, so they fit naturally in the chapter. While contest problem setters may like to confuse contestants with long stories and convoluted descriptions, there’s no reason a programming book has to do the same thing.
How to Use Contest Problems
If you’re reading a book that has contest problems as examples, you can use them in several ways that aren’t available for problems written specifically for a book. Contest problems, if chosen correctly, are found on online judges. So you can try solving them yourself before reading the book section. This can help you pinpoint the areas you’re having trouble with, which you can then focus on when reading the section. Once you read the author’s ideas, you can adjust your implementation and re-submit as many times as you want. This is a good way to experiment with language features and learn how an algorithm works. As Dr. Zingaro writes, “If you make changes and the code no longer passes the tests, great! Now you have a new learning opportunity to fix the code and learn why your changes led to undesired behavior.” Finally, publicly available problems often have publicly available solutions, whether on the online judge’s website, or on blogs and in GitHub repos. Once you’re familiar with a problem, you can review other people’s solutions to see what they did differently. You might find the most useful ideas not in the book you’re reading, or in the official editorial, but from a creative programmer in the discussion forums.
Like the well-known competitive programming book called Competitive Programming, Learn to Code by Solving Problems has contest problems both in the main text of each chapter and at the end of the chapter. While you won’t find the same detailed explanations for the end-of-chapter problems as you get for the problems in the main text, it’s still useful to have a curated list of quality problems that illustrate a particular programming concept. And since these problems are also available on online judges, they have the same benefits: automated judging, repeated submissions, and crowdsourced solutions.
Programming Tips
Although Learn to Code by Solving Problems is for beginners, and targets at a wide range of programmers (not just computer science students), it doesn’t avoid discussions of programming fundamentals or algorithm basics. The later chapters cover hash tables, binary search, and big O analysis. And the earlier chapters are careful to explain programming best practices and details of the Python language to help you write idiomatic and reliable code. We learn that Python string comparison is case-sensitive by default, that programmers should “Whenever possible, write code that doesn’t require comments,” that Python supports negative indexes, that the break statement only terminates “its own loop, not any outer loops,” that Python strings are immutable while Python lists are immutable, and how passing by value differs from passing by reference. Dr. Zingaro even takes a position on the great tabs vs. spaces debate (the verdict: spaces, though maybe that’s just because it’s in the Python style guide).
Practice, practice, practice
For someone just learning to program, or learning Python after spending some time with another language, Learn to Code by Solving Problems covers what a programmer needs to know to get started with the language, plus language-independent skills like breaking a solution into parts using functions. But programming can be tricky at any skill level. People learning to program or learning a new programming language in this era have the advantage of an abundance of online judge problems for practice. Programming educators and students would do well to embrace that mode of learning.