The process your mind takes to understand the image is much shorter than to understand the expression.
The same happens when actively creating something. It’s easier for you to come up with a solution while using your eyes and hands on the paper than directly trying to express it in code.
Furthermore, when you design before writing, you can debug more easily. The design offers you a panoramic view of the algorithm, which you can contrast with the code in successive iterations, to recognize the nature of the error.
If you’re already convinced to pick up that pen and paper, you might find useful some tips for the process.
There are several ways to do this. In fact, Software Engineering offers a lot of different models on how to design software and abstract architectures to approach a lot of different problems. Here I want to give a very generic method, on which almost any other process is based.
What information do you have and how you want/need to represent it? Are you going to use predefined types or structures of the language? Do you need to define your own?
What are the basic operations you can perform on this information? You should be clear on what transformations you can apply to your data.
In many languages the most basic is asignation. Be sure to understand how it works. The rest usually depends on whether it is a number, a string, a collection, an object, etc
You will be able to use these basic operations as the building blocks of your algorithm.
These are not sequential steps, but separate advice to develop your solutions.
Before even trying to define the algorithm, it is better to have some examples of input and output. For this you can also specify some preconditions and postconditions: What is true before the algorithm is executed? What must be true after the algorithm is executed?
You don’t need to think it straight from the first to the last step. Sometimes the last part of the algorithm is clearer than the first one. Go ahead and specify its latter part, and then focus on how to get to that point.
Divide the problem into subproblems until you are able to solve them with your basic operations. You can write first a high-level pseudocode or flow-chart version of the solution, and then go through each step, decomposing it into more steps.
Different minds deal better with different methods, but in the end, learning and practising are the two only ways to improve.
There is a direct synergy between solving problems and programming, but always remember: the solution can exist without the code; the code can’t exist without the solution.