AlgoMaster Logo

How to Approach Logic Problems

10 min readUpdated June 23, 2026
Listen to this chapter
Unlock Audio

Knowing a language's syntax is one skill. Turning a problem written in plain English into working code is a different one. This chapter gives you a repeatable process for reading a worded problem, planning a solution, and turning that plan into code that runs correctly.

This chapter covers:

  • A five-step process to go from a worded problem to working code
  • How to choose between a for loop and a while loop
  • How to translate English phrases into boolean conditions
  • A practical debugging mindset for when your code is wrong
  • When to extract logic into a helper function and when to keep it inline

A Repeatable Process: Read, Restate, Trace, Code, Test

Simple coding problems become easier when you stop writing code immediately. Jumping straight to the keyboard leads to off-by-one errors, wrong conditions, and code that solves the wrong problem. A short, repeatable process prevents those mistakes.

The process has five steps: read, restate, trace, code, and test. The diagram below shows how they connect.

Let us apply all five steps to one small problem: find the sum of all even numbers from 1 to n.

Step 1: Read the Problem Carefully

Read the full problem before deciding anything. Note the input, the output, and any limits. For our example, the input is a single number n and the output is the sum. The word "even" matters, because odd numbers are excluded. The range "from 1 to n" is inclusive on both ends.

Missing one word like "even" or "inclusive" sends you down the wrong path before the first line.

Step 2: Restate It in Your Own Words

Say the problem back to yourself in plain language. For our example: "Walk through every number from 1 up to and including n. Whenever a number divides evenly by 2, add it to a running total. Return that total."

If you cannot restate it cleanly, you do not understand it well enough to solve it yet. Go back to step 1.

Step 3: Trace It by Hand on a Small Input

Pick a small input and work the answer out on paper. For n = 6, the even numbers are 2, 4, and 6, summing to 12. The table below shows the running total at each step.

Scroll

Number

Even?

Running total

1

no

0

2

yes

2

3

no

2

4

yes

6

5

no

6

6

yes

12

You now have an expected answer of 12 for n = 6 to check your code against.

Step 4: Write the Code

The hand trace maps directly to code: a running total starting at 0, a loop over every number from 1 to n, an evenness check, and an addition when it passes.

Each part of the code lines up with the trace. The variable total is the running total column, the loop walks the number column, and the if check is the "Even?" column. Once the trace is done, writing the code is mechanical.

Step 5: Test Against Edge Cases

Run your code on the input you traced by hand. For n = 6, it should return 12. If it does, try the inputs that sit at the boundaries of the problem:

  • n = 1: no even numbers in range, so the answer is 0.
  • n = 2: the only even number is 2, so the answer is 2.
  • n = 0: the loop never runs, so the answer is 0.

If any of these fail, return to the start of the loop. Re-read the problem, fix your understanding, and trace again. The arrow from "Test" back to "Read" in the diagram is the part beginners skip, and it is where most bugs get caught.

Picking the Right Loop: for vs while

Almost every warmup problem involves repetition. The choice of loop comes down to one question: do you know how many times the loop will run before it starts?

When the iteration count is fixed and known up front, use a for loop. Counting from 1 to n, visiting every element of an array, or repeating an action exactly k times all give you the count in advance.

When you loop until some condition becomes true and cannot predict how many steps that takes, use a while loop. Peeling digits off a number one at a time until it reaches 0 is a clear example, since you do not know how many digits the number has until you start removing them.

Scroll

 

for loop

while loop

Use when

Iteration count is known up front

You loop until a condition is met

Driven by

A counter that increments

A condition that changes inside the loop

Typical examples

Count 1 to n, walk an array

Process digits of a number, read until end

Here is a counting for loop that prints the numbers 1 through 5. The count is known before the loop begins.

Here is a condition-driven while loop that removes digits from a number until nothing is left. The number num starts at 472, and each pass strips off its last digit. The loop stops when num reaches 0, but the code does not know in advance that this takes three passes.

This prints 2, then 7, then 4. The modulo operator % pulls off the last digit, and integer division by 10 shifts the rest right. A for loop would be awkward here because the iteration count depends on how many digits the input has.

Translating Words into Conditions

A worded problem often hides a boolean condition inside an English phrase. Spotting these phrases and converting them into code is a core part of turning problems into solutions. The table below maps common phrases to the conditions they represent.

English phrase

Code condition

x is even

x % 2 == 0

x is odd

x % 2 != 0

x is divisible by d

x % d == 0

x is between a and b (inclusive)

x >= a && x <= b

x is at least a

x >= a

x is at most b

x <= b

x is positive

x > 0

x and y are both positive

x > 0 && y > 0

x is zero or negative

x <= 0

A few deserve a closer look. "Divisible by" almost always means the remainder is 0, which the modulo operator gives directly. The word "inclusive" controls whether you use < or <=. "Between a and b" usually means inclusive on both ends, so it becomes two comparisons joined with &&. When two things must both hold, combine them with && (and); when either one is enough, use || (or).

Once you can translate a phrase like "count the numbers between 10 and 50 that are divisible by 7" into n >= 10 && n <= 50 && n % 7 == 0, the rest of the problem is a loop around that condition.

A Debugging Mindset: Print, Trace, Dry-Run

Code rarely works on the first try, so finding why it is wrong matters as much as writing it. Three techniques do most of the work.

Add print statements to see intermediate values. A wrong final number tells you nothing about where it went wrong. Print the variables inside the loop to watch how they change.

Running this shows the running total after every step. If the printed values stop matching your hand trace at, say, i = 4, the bug is in how step 4 is handled. The print narrows the search from the whole program to a single line.

Dry-run on paper. Pick a small input and execute the code by hand, line by line, writing down each variable as it changes. This is the trace from step 3, now applied to the exact code you wrote rather than the plan. A dry-run catches bugs prints cannot, because it forces you to read what the code does instead of what you meant it to do.

Check the boundaries. Most bugs hide at the edges of the input range, not the middle. Test these cases deliberately:

  • Zero: does the loop behave when the input is 0?
  • One: the smallest non-trivial case often exposes off-by-one errors.
  • Negative numbers: does the code assume the input is positive?
  • Empty input: an empty array or a count of 0 should not crash.

A program that handles n = 100 correctly can still fail on n = 0 or n = 1. Testing the boundaries first finds those failures fast.

Helper Function vs Inline Code

As problems grow, you face a choice: keep all the logic in one block, or pull a piece into a small helper function. The answer depends on whether the logic is reused and whether it forms a self-contained sub-step.

Pull logic into a helper function when:

  • The same logic is needed in more than one place. Writing it once and calling it twice avoids duplicated code that can drift out of sync.
  • The logic is a self-contained sub-step with a clear name, such as "count the digits of a number" or "check whether a number is prime." A named helper makes the main code read like a description of the steps.

Keep logic inline when:

  • It is used only once and is short enough to read at a glance.
  • Extracting it would add a function call without making the code clearer.

Consider a problem that needs a number's digit count in two places. The digit-counting logic is both reusable and a clean sub-step, so it belongs in a helper.

With this helper in place, the main code calls countDigits(472) and gets 3 without restating the loop. If the problem only counted digits once, as a small part of a larger loop, leaving the while loop inline would be fine, since extracting it would add a layer without paying for itself.

A practical rule: write the logic inline first. When you find yourself copying it to a second spot, or when a block grows large enough that a name would explain it better than the code does, move it into a helper.

Where This Leads

You now have a process for reading a worded problem, a way to choose the right loop, a method for turning English into conditions, a debugging routine, and a sense of when to reach for a helper. These tools apply on every problem that follows.

The next set of problems puts each idea into practice on small, focused tasks: printing sequences of numbers, summing values across a range, and working with the individual digits of an integer. Each one is small enough to trace by hand and solve in a single loop, a good place to build the habits from this chapter before the problems grow.