Topics › Basics › Things to Know in C++/Java/Python or any language

For loops

Easy TUF ID 2867 A2Z

What this covers

A for loop repeats a block of code a number of times that is known, or at least bounded, before the loop starts: once per index of an array, once per row of a grid, once per candidate value from 1 to n. This article covers the anatomy of the counting loop, the enhanced for over collections and arrays, loops with two variables, nested loops and how to count their work, and the three control statements that change the flow: break, continue and labeled break. Each construct is shown on a small task that reappears constantly in the sheets.

Anatomy of the counting loop

for (init; condition; update) body runs init once, then repeats: test condition, if true run body, run update. The condition is checked before every pass, including the first, so a loop whose condition is false initially runs zero times.

static long sumTo(int n) {
    long sum = 0;
    for (int i = 1; i <= n; i++) sum += i;
    return sum;
}

For n = 0 or a negative n, 1 <= n is false and the sum stays 0. The variable i declared in the header exists only inside the loop. The sum is a long because sumTo(100000) is 5000050000, well past the int limit.

Going downward is a matter of changing the three header parts: start high, test >=, decrement.

static String countdown(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = n; i >= 1; i--) {
        sb.append(i);
        if (i > 1) sb.append(' ');
    }
    return sb.toString();
}

The enhanced for

When you need each element but not its position, for (type x : array) hands you the elements in order. It is shorter and removes the possibility of an off-by-one error in the bounds.

static int maxElement(int[] a) {
    int best = Integer.MIN_VALUE;
    for (int x : a) if (x > best) best = x;
    return best;
}

Starting best at Integer.MIN_VALUE means a single-element array returns that element and an all-negative array still works; an empty array returns the sentinel itself, which the caller must be prepared for. Two limits of the enhanced loop: x is a copy, so assigning to it does not change the array, and there is no index, so you cannot look at neighbours or write back.

Two variables in one header

The init and update parts may contain several comma-separated pieces. This is the natural way to walk inward from both ends:

static boolean isPalindrome(int[] a) {
    for (int i = 0, j = a.length - 1; i < j; i++, j--) {
        if (a[i] != a[j]) return false;
    }
    return true;
}

The condition i < j stops when the pointers meet or cross; the middle element of an odd-length array is never compared to anything, which is correct. An empty array has j = -1, the condition fails at once, and true is returned.

break: leave early

break ends the loop immediately. Use it when the loop’s purpose is to find something and further iterations would be wasted work.

static int firstNegativeIndex(int[] a) {
    int found = -1;
    for (int i = 0; i < a.length; i++) {
        if (a[i] < 0) {
            found = i;
            break;
        }
    }
    return found;
}

In a method like this return i; inside the loop is even shorter, but break is the tool when more work follows the loop. The sentinel -1 for “not found” is a convention worth adopting, since it can never be a valid index.

continue: skip this pass

continue jumps to the update step and the next condition check, skipping the rest of the body. It keeps the “interesting” code at a shallow indentation instead of wrapping it in an if.

static long sumOfOdds(int[] a) {
    long sum = 0;
    for (int x : a) {
        if (x % 2 == 0) continue;
        sum += x;
    }
    return sum;
}

x % 2 == 0 is the correct evenness test for negative numbers too: -3 % 2 is -1, not 0, so -3 is counted as odd. Testing x % 2 == 1 would have missed it.

Nested loops

A loop inside a loop runs the inner body once for every combination. The classic use is examining every pair of elements; starting the inner index at i + 1 ensures each unordered pair is seen exactly once and no element is paired with itself.

static int countPairsWithSum(int[] a, int target) {
    int count = 0;
    for (int i = 0; i < a.length; i++) {
        for (int j = i + 1; j < a.length; j++) {
            if (a[i] + a[j] == target) count++;
        }
    }
    return count;
}

The inner loop runs n - 1, n - 2, ..., 1, 0 times, in total n(n - 1) / 2 iterations, which is O(n^2). For n = 10^5 that is 5 × 10^9 steps, far too many; this is exactly the brute force that Two Sum improves on with a hash map. Nested loops also build grids, where the outer loop chooses the row and the inner loop fills it:

static String multiplicationTable(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (j > 1) sb.append(' ');
            sb.append(i * j);
        }
        sb.append('\n');
    }
    return sb.toString();
}

The newline is appended after the inner loop finishes, once per row. Confusing “per row” work with “per cell” work is the usual source of malformed grid output.

Labeled break: leave two loops at once

A plain break inside the inner loop only leaves the inner loop; the outer loop carries on with its next row. To stop both, put a label before the outer loop and break to it.

static int[] findInGrid(int[][] grid, int target) {
    int[] pos = {-1, -1};
    outer:
    for (int r = 0; r < grid.length; r++) {
        for (int c = 0; c < grid[r].length; c++) {
            if (grid[r][c] == target) {
                pos = new int[]{r, c};
                break outer;
            }
        }
    }
    return pos;
}

The alternative is to move the loops into their own method and return from inside; that is often cleaner, but the label is the right tool when the loops must stay inline.

Edge cases and pitfalls