3 months ago, I started my 90 day problem-solving challenge. The goal was to improve my programming as well as problem-solving skills by solving numerous challenges with increasing difficulty.
I never thought I would have so much fun and suffer at the same time. It's been a blast. Let me share with you what I did and how I did it!
I used the Codingame platform to dive into different algorithmic challenges. As a programming language I chose Python.
I challenged myself to finish the following number of challenges with different difficulties:
Levels | Goal ---------|------ Easy | 5 Medium | 3 Hard | 2
I wanted to finish 5 easy, 3 medium and 2 hard problems. Seeing that I had never followed a challenge like this, I knew this was no easy task. I've never felt capable or good at solving difficult problems. All of my experiences have showed me that I'm not very adept. Not very good at it.
This was not only my impression. I validated all throughout the journey. Time and time again.
I jotted down my thoughts during the process. This was one of the first ones:
It’s strange. I seem to be completely incompetent to develop solutions to even easy problems. When I look at its solution and I realize how easy it actually is. But I can't find the solution myself.
Others were less self-doubts about my intellectual capacities but more about my systemic approach to problem solving. As I worked throughout the day I would try to spend the maximum amount of time at night on thinking and trying to solve the problem.
But I underestimated the cyclical nature of my energy.
I’m falling asleep as I’m trying to focus on the problem at hand.
This was not the exception, but rather the norm. I so often fell asleep as I was forcing myself to focus on a problem. It seemed my body and mind did not want to engage in those very demanding tasks.
But slowly I managed to solve the first easy challenges. I used each success that I had to build up on it, to most importantly tell myself that I'm not a complete idiot. That with enough time and effort, I can finish those challenges.
The Problem Solving Approach
To solve those challenges I had to come up with an approach on how to master them. Looking back on it, I realize that certain things have been crucial in helping me solve the challenges.
My default approach of solving a problem was to get started right away. To jump in. To directly program what comes to mind.
# Beginners approach to problem solving def solveProblem(): define problem build solution
I have learned that this is not the best approach.
Because it's built on the premise that the first time around you have a) identified all constraints and b) completely understood the problem.
Both were never the case for me.
Throughout the challenged I've learned that the following approach is better.
# Improved approach to problem solving def solveProblem(): while solution does not satisfy all conditions: understand problem define solution test solution build solution
The first approach to solve a problem was linear
define problem -> build solution, but this new approach is circular.
You have to refine the
understand problem -> define solution -> test solution part until it meets all the said criteria. Only then do you go on to build the solution.
On your path to implementing this, your biggest helper is exploration.
Exploration is the Key to Problem Solving
Exploration is the answer to the question, "how do I find the core issue to the problem?" Not only is it the answer, but also the path to the solution.
If I had an hour to solve a problem I'd spend 55 minutes thinking about the problem and 5 minutes thinking about solutions.
Exploration is thinking, deeply thinking, about the problem.
Exploration = Understand problem + define solution + test solution
It is what we defined above as the 3 steps we have to repeat over and over until our thoughts represent a solution to the problem. We can, thus, re-write the formula as:
def solveProblem(): while solution does not satisfy all conditions: explore problem build solution
But how do we explore a problem.
Tools to Explore a Problem Quickly
There is no single right answer as to how you should start your discovery process. The only thing I can point you to are tools that help you on the way. Use them as starting points and build upon them.
1. Identify the Constraints
Every problem has constraints. Constraints are hugely useful because they help you identify the nature of the challenge at hand quickly. Without understanding the constraints you will go round and round in a circle.
Sometimes constraints can be easily identified, as is the case with the Codingame, since they give them to you.
# Constraints for variables provided for the Super Computer challenge 0 < N < 100000 0 < J < 1000000 0 < D < 1000
It's hard to move forward without having identified the restrictions.
The constraints above, without looking at any other information, seem to be on an optimization problem, simply due to the sheer number that the variables can contain.
Edge cases can be useful as they will bring you to the limits, i.e. edges, of the problem. A typical edge case in a number problem tends to be 0. You can't divide by 0. 0 will cause a loop to never run, if it's part of a condition for the number to be above 0.
They can help you refine your understanding of the world and its limits.
2. Test Yourself, and Your Program
Think in terms of input vs output. What does the program require as input, how is it transformed and what do I need to output?
# How do you need to transform the input into output? Input -> Program -> Output
Thinking along those lines will help you gain a better understand of the problem. This can be as easy as writing down the output you need to get for a certain input.
Input: 3, 3, 4 Output: 4
Then follow calculate, step by step, as to how you get to the result manually. Do this for another input and output. Compare the two and see what you've done. Use the patterns you see to create pseudo code.
Now, repeat this for a third example. See where you were wrong and correct your pseudo code. Then rinse and repeat.
3. Visualization and Thought Experiments
These two are probably the biggest assets I have to solve problems. They allow me to clarify my thinking, identify flaws and build upon existing ideas.
Two sources that can pinpoint you in the right direction are:
- How Einstein Learned Physics, Source: scotthyoung.com
- The Beginner Programmer's Guide to Problem Solving, Source: codeproject.com
4. Flush Your Memory onto Paper
From time to time, as you are diving into the problem, it's important to clear your head. Write your ideas down on paper. Jot them down. Draw something. Just do what you have to get your thoughts onto a permanent medium.
Flushing your brain helps as it clears your short-term memory. It makes room for new thoughts and allows you to build on top of your existing ones.
When you find yourself at an impasse:
- simply try to go through the issue once more. Read how the problem is stated. And restart.
- create a reduced down version of the problem. A less complex one. Start from there.
When you suffer, contemplate this thought: When you feel incompetent, you are on the right track. It means you are pushing your limits.
So what was the result of all of this?
Levels | Goal | Solved ---------|------|--------- Easy | 5 | 10 Medium | 3 | 5 Hard | 2 | 0
In the end, I solved 10 easy, 5 medium and 0 hard ones. While I managed to solve a lot more of the easier ones, I didn't manage to solve the hard ones.
Exponential Difficulty - My Fault
There were a decent amount of errors I committed along the journey.
As I really wanted to develop my problem solving skills, I went for increasingly more difficult problems. I'm glad I did. But the mistake I made as I went about doing so was that I thought that the difficulty would increase linear.
It turned out that it increased exponentially.
What I should have done was, specifically at more difficult levels, to follow series of challenges, of which I've solved the easier levels. For example, I should have tried to solve the Skynet Revolution 2 challenge, as I've already mastered the Skynet Revolution 1 challenge. It would have made the transition easier, while giving me the impression of actually advancing.
- Refactor my existing code by taking a look at the optimal solutions and improving upon my code.
I now understand how important it is to have good problem solving skills. It is essential these days. It's one of the basic building blocks of becoming adept at technology