Topics › Basics › Things to Know in C++/Java/Python or any language
For loops
Java source ↗ Edit this article ↗
Jump to code:
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
- Off by one.
i < nvisits0..n-1;i <= nvisits one more and throws on arrays. Decide whether the bound is inclusive and write the comparison to match. - Zero iterations. A
forloop whose condition is false at the start runs zero times. Make sure the code after the loop is correct for that case (empty sums are0, empty maxima need a sentinel). - Modifying the loop variable in the body. Legal but confusing; prefer a
whileloop when the step is irregular. - Overflow in accumulators. Sums and products over many iterations need
long. - Enhanced for cannot write. Assigning to the loop variable changes a copy. Use an index loop to modify elements.
- Nested loop cost. Two nested loops over
nareO(n^2); three areO(n^3). Know the input size before choosing this shape. - Mutating a collection while iterating it. Removing from an
ArrayListinside an enhanced for throwsConcurrentModificationException; iterate by index backwards or use an iterator.
Related problems
- While loops covers loops whose number of passes is not known in advance.
- Easy and Medium applies nested loops to pattern printing, the classic drill for row and column reasoning.
- Two Sum starts from the nested-loop pair count above and shows how to make it linear.
- What are arrays, strings? covers the arrays these loops walk over.