Counting loops summary

A lot of College Board problems depend on being able to tell how many times a loop runs. Below I’ve cataloged a number of kinds of loops in order of increasing complexity with information about how to figure out how many times a loop will run using a bit of simple math. Note that if you skip to the section on “Step loops” and master the formula for the most general form it handles the first two kinds of loops as well.

Remember that counting loops can also be written as while loops. For those while loops you can use the formulas in this document as long as you identify the initializer (usually a variable declaration right before the while), the condition (that’s easy, it’s in the while), and the updater (usually the last line of the body). However not all while loops are simple counting loops. (For that matter, not all for loops are either so the first thing you may need to check when looking at any loop is whether it’s a counting loop in the sense of having a loop variable that starts at a number and goes to another number in uniform steps.)

Simple counting loops

These loops loop up or down from or to 0 or sometimes 1. They are the most common loops, used to iterate over the elements of a String, array, or ArrayList. You should be able to look at loops like these, especially the three upward loops, and tell almost instantly how many times the loop body will run.

Loop style Number of iterations Values of i
for (int i = 0; i < num; i++) {}
          
num 0 up to num - 1, inclusive.
for (int i = 1; i <= num; i++) {}
          
num 1 up to num, inclusive
for (int i = num; i > 0; i--) {}
          
num num down to 1, inclusive
for (int i = 0; i <= num; i++) {}
          
num + 1 0 up to num, inclusive.
for (int i = num; i >= 0; i--) {}
          
num + 1 num down to 0, inclusive

Range loops

These loops are similar to simple counting loops but they start at some arbitrary number other than 0 or 1. They are useful for iterating over a substring of a String or a subsection of an array or ArrayList. You have to do a bit of subtraction to figure out how many times the loop body will run.

Loop style Number of iterations Values of i
for (int i = start; i < end; i++) {}
          
end - start start up to end - 1, inclusive
for (int i = start; i <= end; i++) {}
          
(end - start) + 1 start up to end, inclusive
for (int i = start; i > end; i--) {}
          
start - end start down to end + 1, inclusive
for (int i = start; i >= end; i--) {}
          
(start - end) + 1 start down to end, inclusive

Step loops

The final generalization of counting loops, step loops are like range loops with the added wrinkle that the loop variable is incremented or decremented by some number other than 1. If start. and end are multiples of step these can be converted to a simple or range loop and then in the body of the loop instead of using the loop variable use the loop variable times step. This can often make the code easier to read because it’s easier to understand how many times the loop will run just by looking at the loop header.

If start and end are not multiples of step you need to think more carefully about when the loop will end. But in either case the formulas below will let you figure out with one subtraction, and one rounding division how many times the loop body will run.

Loop style Number of iterations Values of i
for (int i = start; i < end; i += step) {}
          
(end - start) / step, rounded up start plus multiples of step
for (int i = start; i > end; i -= step) {}
          
(start - end) / step, rounded up start minus multiples of step
for (int i = start; i <= end; i += step) {}
          
((end - start) + 1) / step, rounded up start plus multiples of step
for (int i = start; i >= end; i -= step) {}
          
((start - end) + 1) / step, rounded up start minus multiples of step

Note that when the comparator is < or > the number of iterations is the larger index minus the smaller index divided by the step size and when it’s <= or >= we subtract the smaller from the larger and then add one before dividing by step size. And in either case, we round up after dividing. This formula works for all the other kinds of loops which are just more specific cases of these step loop forms with step being 1 and—in the case of simple loops—one of start or end being 0 or 1 which makes the subtraction pretty easy.

Nested loops

When we talk about how many times a nested loop runs we usually mean the body of the innermost loop. The only trick to analyzing such loops, is to correctly analyze both the outer and inner loops and then multiply the number of times each loop runs. For instance:

for (int i = 0; i < 10; i++) {
  for (int j = 0; j < 12; j++) {
    System.out.print("*");
  }
}
  

It’s easy to see that the outer loop runs 10 times and the inner loop runs 12 times. Thus the call to System.out.print will happen 10 x 12 or 120 times.

Obviously if the loops are more complex it won’t be as easy to read off the number of times but we can still analyze each loop independently. Consider, for instance, this mess:

int i = 38;
while (i >= -17) {
  for (int j = -13; j < 15; j += 3) {
    System.out.print("*");
  }
  i -= 5;
}
  

We can analyze the outer loop as a step loop from 38 down to -17 by 5 with a >= in the condition. So ((38 - -17) + 1) / 5 or 56/5 which gives us a bit more than 11 so 12 iterations. And the inner loop is from -13 up to 15 by 3’s with a < in the condition so (15 - -13) / 3 or 28 / 3 which is 9 and a bit so rounding up gives us 10. Now 12 times 10 gives us 120 for the number of times the inner body of these nested loops will be run.

Array/ArrayList/String loop recipes

Below are some common patterns for traversing 1D and 2D arrays. These also work with ArrayLists, if you replace a.length with list.size()and a[i] with list.get(i). And the one-dimensional recipes work with Strings, if you replace a.length with s.length() and a[i] with s.substring(i, i + 1).

Loop style Purpose
for (int i = 0; i < a.length; i++) {
  // do something with a[i]
}
          
Traverse array in normal order.
for (int i = a.length - 1; i >= 0; i--) {
// do something with a[i]
}
          
Traverse array in reverse order.
for (int row = 0; row < a.length; row++) {
  for (int col = 0; col < a[0].length; col++) {
    // do something with a[row][col]
  }
}
          
Traverse 2D array from top left to bottom right by row (sometimes called “row major order”). I.e. processes all the elements in the 0th row, then all the elements in the 1st row, and so on. Assumes the 2D array is rectangular (i.e. all the rows are the same length).
for (int row = a.length - 1; row >= 0; row++) {
  for (int col = 0; col < a[0].length; col++) {
    // do something with a[row][col]
  }
}
          
Same as previous but processes the rows from last to first. Columns are still left to right. (This is not a particularly common thing to do but the College Board likes to mix things up.)
for (int col = 0; col < a[0].length; row++) {
  for (int row = 0; row < a.length; row++) {
    // do something with a[row][col]
  }
}
          
Traverse 2D array from top left to bottom right by column (sometimes called “column major order”). I.e. processes all the elements in the 0th column, then all the elements in the 1st column, and so on. Assumes the 2D array is rectangular (i.e. all the rows are the same length).
for (int i = 0; i < a.length; i++) {
  for (int j = 0; j < a.length; j++) {
    // do something with a[i] and a[j]
  }
}
          
Process each pair of elements in a 1D array, where pairs are processed in the both orders (e.g. a[0] and a[1] and also a[1] and a[0]. Will also process the pairs made of pairing each element with itself, i.e. a[0] and a[0].
for (int i = 0; i < a.length; i++) {
  for (int j = i + 1; j < a.length; j++) {
    // do something with a[i] and a[j]
  }
}
          
Process each unique pair of different elements in a 1D array ignoring order. In each pair a[i] and a[j] the element earlier in the array comes first. Does not pair elements with themselves.

String-specific loop recipes

Loop style Purpose
for (int i = 0; i < s.length(); i++) {
  for (int j = i + 1; j <= s.length(); j++) {
    // do something with s.substring(i, j)
  }
}
          
Process all non-empty substrings of the String s. Note the <= rather than < in the inner loop since we want the second argument to substring to go all the way to the end of the string.
for (int i = 0; i <= s.length(); i++) {
  // do something with s.substring(0, i)
}
          
Process all prefixes of the String s. Includes the empty prefix ””. Change initialization of i to i = 1 to exclude the empty prefix.
for (int i = 0; i <= s.length(); i++) {
  // do something with s.substring(i)
}
          
Process all suffixes of the String s. Includes the empty suffix ””. Change the <= in the condition to < to exclude the empty suffix.