DSA — Before You Start

Logic Building Before DSA

Six phases of problems that need no data structure you have not met — just conditions, loops, recursion and a list. The rung between syntax and algorithms.

Foundations ✓ Start here 36 problems Before Big-O
01

Why Logic Before Data Structures

Most people who stall on their first DSA problem do not lack knowledge of arrays. They lack the habit of turning a sentence into steps. You can recite what a hash map is and still freeze at "find the first non-repeating character", because the gap is not the structure — it is the reasoning that decides to use one.

This page is the rung between knowing your language's syntax and starting Big-O. Six phases, each one a small set of problems that can be solved with nothing but conditions, loops, recursion and a list. No data structure you have not met yet, no algorithm names — just the thinking.

How to use it: solve on paper first, then type. If you cannot describe the steps in a sentence, writing code will not rescue you — it will only hide the fact that the plan is missing.
02

The Dry Run — Your Most Useful Tool

A dry run is tracing your code by hand, one line at a time, writing down what every variable holds after each step. It is the single technique that separates people who debug quickly from people who guess.

Trace this by hand before running it
def mystery(n):
    total = 0
    while n > 0:
        total = total + (n % 10)
        n = n // 10
    return total

mystery(472)

Now the trace table. One row per pass, one column per variable:

Passn at startn % 10total aftern after
147220 + 2 = 247
24772 + 7 = 94
3449 + 4 = 130
0loop ends13

Three rows and the function names itself: it sums the digits. You now also know the loop runs once per digit, which is the beginning of complexity analysis without the vocabulary.

When a solution is wrong, do not re-read it hoping to spot the bug. Trace it with the smallest input that fails. The row where the table stops matching your expectation is the line with the bug — every time.

Two habits worth forming alongside it. Pseudocode first: write the steps in plain language, then translate. And know your edge cases before you start — zero, one element, empty input, negatives, duplicates, the largest value. Most failed submissions are correct logic meeting an input the author never considered.

03

Phase 1 — Conditions & Boolean Logic

Goal: make a decision correctly, including when several conditions interact.

What you are practising: relational operators, and / or / not, nested conditions, ordering your checks so the first true branch is the right one.

The ordering trap
# Wrong: 95 prints "Pass", because the first true branch wins
if score >= 40: print("Pass")
elif score >= 75: print("Distinction")

# Right: test the narrowest condition first
if score >= 75: print("Distinction")
elif score >= 40: print("Pass")

Work through these:

  1. Print whether a number is positive, negative or zero — three outcomes, not two.
  2. Decide whether a year is a leap year. The rule has three parts and most people get the century case wrong.
  3. Take three numbers and print the largest, without using a built-in max.
  4. Classify a character as uppercase, lowercase, digit or symbol.
  5. Given three side lengths, decide whether they form a triangle, and if so whether it is equilateral, isosceles or scalene.
  6. Given a temperature and whether it is raining, decide between four clothing recommendations. Write the conditions so no input falls through with no answer.
04

Phase 2 — Loops & Patterns

Goal: repeat work deliberately, and know how many times the body will run before you press run.

What you are practising: for and while, accumulator variables, nested loops, break and continue, and reading a loop by its invariant.

The accumulator pattern — the shape of half of these
total = 0                 # start from the identity
for d in digits:
    total = total + d     # one step per item
print(total)

A nested loop is not twice the work — it is the work squared. Two loops over the same n items run n² times, which is why a pattern that prints instantly for 10 rows crawls at 10,000.

Work through these:

  1. Print the multiplication table for a number, then for every number to 10 — the second is the first inside another loop.
  2. Sum the digits of a number, then reverse it. Both are the same loop with a different accumulator.
  3. Decide whether a number is prime. Then find every prime below 100. Stop the inner loop as soon as you know the answer.
  4. Print a right triangle of stars, then a pyramid. Work out the spaces before the stars on paper first.
  5. Compute a factorial with a loop, then the first n Fibonacci numbers.
  6. Given a series of inputs ending in zero, report the count, sum, largest and smallest in a single pass.
05

Phase 3 — Recursion

Goal: solve a problem by describing it in terms of a smaller version of itself.

What you are practising: the base case, the recursive step, trusting the call, and seeing the call stack unwind.

Every recursive function is these two lines
def factorial(n):
    if n <= 1: return 1        # base case: the smallest problem, answered directly
    return n * factorial(n - 1)  # recursive step: assume it works for n-1
Missing or unreachable base case is the whole of recursion debugging. If the argument does not move toward the base on every call, you get a stack overflow — trace three levels by hand and you will see it immediately.

Work through these:

  1. Factorial and the nth Fibonacci number. Then trace how many calls Fibonacci makes for n = 6, and see why it explodes.
  2. Sum the digits of a number recursively — the same problem as Phase 2, now without a loop.
  3. Reverse a string recursively.
  4. Decide whether a string is a palindrome, comparing the outermost characters and recursing inward.
  5. Compute the greatest common divisor with Euclid's rule: gcd(a, b) = gcd(b, a mod b).
  6. Print every subset of a small list. Draw the decision tree before writing it — include this element or not.
06

Phase 4 — Arrays

Goal: reason about a collection: visit it, measure it, rearrange it.

What you are practising: traversal, running maximum and minimum, counting occurrences, two indexes moving through one list, in-place changes.

The running-best pattern
largest = items[0]            # never start from 0 — negatives break that
for x in items[1:]:
    if x > largest:
        largest = x

Work through these:

  1. Find the largest and smallest value in one pass, not two.
  2. Find the second largest. The obvious approach fails on duplicates — decide what you want it to do first.
  3. Count how many times each value occurs.
  4. Reverse a list in place, using two indexes that move toward each other.
  5. Move every zero to the end while keeping the order of the rest.
  6. Find the elements that appear in both of two lists, and then those in one but not the other.
07

Phase 5 — Strings

Goal: treat text as a sequence you can measure and rebuild.

What you are practising: indexing and slicing, character classification, building a result piece by piece, comparing two strings.

A string is an array whose elements happen to be characters — every Phase 4 pattern applies. What changes is that in most languages strings are immutable, so "modifying" one means building a new one.

Build, do not mutate
result = ""
for ch in text:
    if ch not in "aeiou":
        result = result + ch    # a new string each time — fine here, O(n^2) at scale

Work through these:

  1. Count the vowels, consonants, digits and spaces in a sentence.
  2. Reverse the words in a sentence without reversing the letters inside them.
  3. Decide whether a string is a palindrome, ignoring case and punctuation.
  4. Find the first character that does not repeat.
  5. Decide whether two strings are anagrams, without using a built-in counter.
  6. Compress a string so that "aaabbc" becomes "a3b2c1", and leave it unchanged when compression would make it longer.
08

Phase 6 — Mixed Challenges

Goal: choose the approach yourself, with no chapter heading telling you which tool to reach for.

What you are practising: everything above, combined — this is what a real interview question feels like.

Solve these without deciding in advance which phase they belong to. That choice is the skill.

Work through these:

  1. Given student marks, report how many passed, the average, and the highest scorer.
  2. Validate a password: minimum length, at least one uppercase, one digit and one symbol. Report which rule failed, not just true or false.
  3. Print the frequency of each digit in a number.
  4. Count the prime numbers in a list.
  5. Print every palindromic word in a sentence.
  6. Given a list of daily temperatures, find the longest run of consecutive rising days.
09

When You Are Ready for DSA

You are ready when you can read a problem, describe the steps aloud, name the edge cases, and trace your solution on paper before running it. Not when you have solved all thirty-six — when the process feels routine.

From here, Big-O Notation gives you the language for the cost you have already been feeling, and Arrays & Strings starts the patterns proper. The DSA roadmap lays out the full order.

Keep the dry-run habit. It stays useful long after these problems stop being hard — it is the same skill you will use on a failing test at work.
10

Quick Quiz

Five questions on the habits, not the syntax.

1. What is a dry run?
2. if score >= 40: "Pass" elif score >= 75: "Distinction" — what does 95 print?
3. A nested loop over the same n items runs how many times?
4. Your recursive function overflows the stack. What is almost always wrong?
5. Finding the largest value, why is starting from largest = 0 a bug?