AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

04 Control flow / Lesson 5 of 5

Loop patterns every program is made of

14 min · +10 XP · 2 exercises · 5 questions

Read the text14 min
Exercises0/2
Quiz5 q

Quick answer

What are the common loop patterns in Java?

The common loop patterns in Java are accumulate, a sum or product seeded with its identity value; count; find the first match with an early exit; all or any; best so far, for a maximum or minimum; two pointers; a sliding window; nested loops over pairs; and reading until a sentinel or end of input. Most interview problems combine two of them.

Most loops are one of a dozen patterns: accumulate, count, find, check all or any, track a best, walk two things at once, generate pairs, read until a sentinel. Recognising the pattern lets you write the loop without thinking about it — and lets an interviewer see that you have. This lesson names them, shows the canonical form of each, and points out the boundary and initial-value traps in each.

Accumulate

long sum = 0;
for (int v : values) sum += v;

double product = 1.0;
for (double f : factors) product *= f;

StringBuilder sb = new StringBuilder();
for (String s : parts) sb.append(s);

The trap is the identity value: 0 for sums, 1 for products, an empty builder for concatenation. And the type: a sum of ints needs a long accumulator when it can overflow (Module 2).

Count

int evens = 0;
for (int v : values) if (v % 2 == 0) evens++;

A count is an accumulate of 1s under a condition. A count over characters, words, or matches is the same shape.

Find (first match)

int index = -1;
for (int i = 0; i < arr.length; i++) {
    if (arr[i] == target) { index = i; break; }
}

Or, better, as a method with return i; and return -1; after the loop. The "not found" value must be one that cannot be a real answer: -1 for indices, null for objects (or Optional, Module 15).

All / any / none

boolean allPositive = true;
for (int v : values) if (v <= 0) { allPositive = false; break; }

boolean anyNegative = false;
for (int v : values) if (v < 0) { anyNegative = true; break; }

Note the initial values: all starts true and looks for a counterexample; any starts false and looks for a witness. Both stop early. On an empty input, all is vacuously true and any is false — the mathematically right answers, and sometimes a surprise. As methods, these are return false; inside the loop and return true; after (for all), and the reverse for any.

Best so far (max / min / argmax)

int max = Integer.MIN_VALUE;
int maxIndex = -1;
for (int i = 0; i < arr.length; i++) {
    if (arr[i] > max) { max = arr[i]; maxIndex = i; }
}

Two ways to seed: with the type's extreme (Integer.MIN_VALUE for a max) or with the first element (max = arr[0], loop from 1 — but then an empty array must be handled first). Seeding with 0 is the classic bug: an all-negative array reports a max of 0. > versus >= decides whether ties keep the first or the last occurrence — say which you want.

Two pointers

int lo = 0, hi = arr.length - 1;
while (lo < hi) {
    if (arr[lo] + arr[hi] == target) return true;
    if (arr[lo] + arr[hi] < target) lo++; else hi--;
}

Two indices moving toward each other (palindromes, pair sums in a sorted array, reversing in place) or in the same direction at different speeds (removing duplicates, sliding windows). The loop condition is lo < hi for "distinct pair", lo <= hi for "may meet".

Sliding window

int best = 0, windowSum = 0;
for (int i = 0; i < arr.length; i++) {
    windowSum += arr[i];
    if (i >= k) windowSum -= arr[i - k];       // drop the element that left the window
    if (i >= k - 1) best = Math.max(best, windowSum);
}

A fixed-size window over an array in one pass: add the incoming element, subtract the outgoing one. The two ifs handle the warm-up while the window is still filling.

Pairs and combinations

for (int i = 0; i < n; i++)
    for (int j = i + 1; j < n; j++)     // j starts at i + 1: each unordered pair once, no (i, i)
        …

j = 0 gives ordered pairs including self-pairs; j = i includes (i, i); j = i + 1 gives each pair once. Getting this bound wrong double-counts or misses the diagonal.

Sentinel and end-of-input

String line;
while ((line = br.readLine()) != null) { … }         // stream ends with null

int x;
while ((x = in.nextInt()) != 0) { … }                 // input ends with a 0 sentinel

while (in.hasNextInt()) { process(in.nextInt()); }    // no sentinel: test availability

The assignment-in-condition idiom (x = read()) != END reads and tests in one step; the parentheses around the assignment are mandatory because != binds tighter than =.

Parallel iteration

for (int i = 0; i < Math.min(a.length, b.length); i++) {
    use(a[i], b[i]);
}

Two sequences in step: index both with one variable, and decide what happens when the lengths differ (stop at the shorter, or check they match up front).

Running state

int prev = arr[0];
for (int i = 1; i < arr.length; i++) {
    if (arr[i] < prev) return false;     // not sorted
    prev = arr[i];
}

Comparing each element with the previous one — sortedness, run detection, deltas. Start at index 1 and seed prev from index 0, after handling the empty case.

Do-something-n-times

for (int i = 0; i < n; i++) sb.append('*');

When the index is unused, some codebases write for (int i = 0; i < n; i++) anyway; "*".repeat(n) and IntStream.range(0, n) are the modern alternatives for the common cases.

Choosing the shape

NeedShape
A total, a product, a concatenationaccumulate with the right identity
How many satisfy Xcount
The first that satisfies Xfind with early exit, return -1/null
Do all / does any satisfy Xall (start true) / any (start false), early exit
The largest/smallest and wherebest-so-far seeded from the first element or the extreme
A pair with a property in sorted datatwo pointers
Best fixed-length runsliding window
Every pairnested with j = i + 1
Read until donesentinel / null / hasNext

Almost every "medium" interview problem is two of these composed. Streams (Module 15) give one-line versions of accumulate, count, find, all/any and max — knowing the loop forms is what lets you read and debug the stream ones.

Key takeaways

  • Seed accumulators with the identity, maxima from the first element or the extreme — never 0.
  • all starts true and hunts for a counterexample; any starts false and hunts for a witness; both exit early.
  • Pairs: j = i + 1. Neighbours: start at 1 with prev. Windows: add incoming, drop outgoing.
  • (x = read()) != END needs its parentheses.

Common questions

How do I find the maximum value in an array in Java?

Seed max with the first element and loop from index 1, or seed it with Integer.MIN_VALUE, and replace it whenever arr[i] > max. Never seed with 0, or an all-negative array reports 0. Comparing with > keeps the first of tied values and >= the last.

What is the two-pointer technique?

Two indices move through an array together, usually from both ends toward each other in a while (lo < hi) loop, to check palindromes, find a pair with a given sum in sorted data or reverse in place. Moving them in the same direction at different speeds removes duplicates.

What is the sliding window technique?

A sliding window keeps a running result over a fixed-length run of elements in one pass: add the element entering the window and subtract the one leaving it, instead of re-summing every window. It finds the best sum of k consecutive elements in linear time.

How do I loop over every pair of elements once?

Nest two loops and start the inner one at i + 1: for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++). That visits each unordered pair exactly once, never pairing an element with itself; starting j at 0 gives ordered pairs, self-pairs included.

Why do all and any loops start with true and false?

An all-check assumes every element passes and hunts for a counterexample, so it starts true and becomes false at the first failure; an any-check starts false and hunts for a single witness. Both can stop early, and on an empty input all is true and any is false.

Mark as readSign in to keep your place.

Java Loop Patterns: Two Pointers, Sliding Window and More

The loop patterns behind most Java programs: accumulate, count, find, all and any, max and min, two pointers, sliding window, pairs and sentinels.

  • Course: Java study plan
  • Module: Control flow
  • Kind: Lesson
  • Reading time: 14 min
  • Runtime: OpenJDK 18

What are the common loop patterns in Java?

The common loop patterns in Java are accumulate, a sum or product seeded with its identity value; count; find the first match with an early exit; all or any; best so far, for a maximum or minimum; two pointers; a sliding window; nested loops over pairs; and reading until a sentinel or end of input. Most interview problems combine two of them.

Lesson

Most loops are one of a dozen patterns: accumulate, count, find, check all or any, track a best, walk two things at once, generate pairs, read until a sentinel. Recognising the pattern lets you write the loop without thinking about it — and lets an interviewer see that you have. This lesson names them, shows the canonical form of each, and points out the boundary and initial-value traps in each.

Accumulate

long sum = 0;
for (int v : values) sum += v;

double product = 1.0;
for (double f : factors) product *= f;

StringBuilder sb = new StringBuilder();
for (String s : parts) sb.append(s);

The trap is the identity value: 0 for sums, 1 for products, an empty builder for concatenation. And the type: a sum of ints needs a long accumulator when it can overflow (Module 2).

Count

int evens = 0;
for (int v : values) if (v % 2 == 0) evens++;

A count is an accumulate of 1s under a condition. A count over characters, words, or matches is the same shape.

Find (first match)

int index = -1;
for (int i = 0; i < arr.length; i++) {
    if (arr[i] == target) { index = i; break; }
}

Or, better, as a method with return i; and return -1; after the loop. The "not found" value must be one that cannot be a real answer: -1 for indices, null for objects (or Optional, Module 15).

All / any / none

boolean allPositive = true;
for (int v : values) if (v <= 0) { allPositive = false; break; }

boolean anyNegative = false;
for (int v : values) if (v < 0) { anyNegative = true; break; }

Note the initial values: all starts true and looks for a counterexample; any starts false and looks for a witness. Both stop early. On an empty input, all is vacuously true and any is false — the mathematically right answers, and sometimes a surprise. As methods, these are return false; inside the loop and return true; after (for all), and the reverse for any.

Best so far (max / min / argmax)

int max = Integer.MIN_VALUE;
int maxIndex = -1;
for (int i = 0; i < arr.length; i++) {
    if (arr[i] > max) { max = arr[i]; maxIndex = i; }
}

Two ways to seed: with the type's extreme (Integer.MIN_VALUE for a max) or with the first element (max = arr[0], loop from 1 — but then an empty array must be handled first). Seeding with 0 is the classic bug: an all-negative array reports a max of 0. > versus >= decides whether ties keep the first or the last occurrence — say which you want.

Two pointers

int lo = 0, hi = arr.length - 1;
while (lo < hi) {
    if (arr[lo] + arr[hi] == target) return true;
    if (arr[lo] + arr[hi] < target) lo++; else hi--;
}

Two indices moving toward each other (palindromes, pair sums in a sorted array, reversing in place) or in the same direction at different speeds (removing duplicates, sliding windows). The loop condition is lo < hi for "distinct pair", lo <= hi for "may meet".

Sliding window

int best = 0, windowSum = 0;
for (int i = 0; i < arr.length; i++) {
    windowSum += arr[i];
    if (i >= k) windowSum -= arr[i - k];       // drop the element that left the window
    if (i >= k - 1) best = Math.max(best, windowSum);
}

A fixed-size window over an array in one pass: add the incoming element, subtract the outgoing one. The two ifs handle the warm-up while the window is still filling.

Pairs and combinations

for (int i = 0; i < n; i++)
    for (int j = i + 1; j < n; j++)     // j starts at i + 1: each unordered pair once, no (i, i)
        …

j = 0 gives ordered pairs including self-pairs; j = i includes (i, i); j = i + 1 gives each pair once. Getting this bound wrong double-counts or misses the diagonal.

Sentinel and end-of-input

String line;
while ((line = br.readLine()) != null) { … }         // stream ends with null

int x;
while ((x = in.nextInt()) != 0) { … }                 // input ends with a 0 sentinel

while (in.hasNextInt()) { process(in.nextInt()); }    // no sentinel: test availability

The assignment-in-condition idiom (x = read()) != END reads and tests in one step; the parentheses around the assignment are mandatory because != binds tighter than =.

Parallel iteration

for (int i = 0; i < Math.min(a.length, b.length); i++) {
    use(a[i], b[i]);
}

Two sequences in step: index both with one variable, and decide what happens when the lengths differ (stop at the shorter, or check they match up front).

Running state

int prev = arr[0];
for (int i = 1; i < arr.length; i++) {
    if (arr[i] < prev) return false;     // not sorted
    prev = arr[i];
}

Comparing each element with the previous one — sortedness, run detection, deltas. Start at index 1 and seed prev from index 0, after handling the empty case.

Do-something-n-times

for (int i = 0; i < n; i++) sb.append('*');

When the index is unused, some codebases write for (int i = 0; i < n; i++) anyway; "*".repeat(n) and IntStream.range(0, n) are the modern alternatives for the common cases.

Choosing the shape

NeedShape
A total, a product, a concatenationaccumulate with the right identity
How many satisfy Xcount
The first that satisfies Xfind with early exit, return -1/null
Do all / does any satisfy Xall (start true) / any (start false), early exit
The largest/smallest and wherebest-so-far seeded from the first element or the extreme
A pair with a property in sorted datatwo pointers
Best fixed-length runsliding window
Every pairnested with j = i + 1
Read until donesentinel / null / hasNext

Almost every "medium" interview problem is two of these composed. Streams (Module 15) give one-line versions of accumulate, count, find, all/any and max — knowing the loop forms is what lets you read and debug the stream ones.

Key takeaways

  • Seed accumulators with the identity, maxima from the first element or the extreme — never 0.
  • all starts true and hunts for a counterexample; any starts false and hunts for a witness; both exit early.
  • Pairs: j = i + 1. Neighbours: start at 1 with prev. Windows: add incoming, drop outgoing.
  • (x = read()) != END needs its parentheses.

Common questions

How do I find the maximum value in an array in Java?

Seed max with the first element and loop from index 1, or seed it with Integer.MIN_VALUE, and replace it whenever arr[i] > max. Never seed with 0, or an all-negative array reports 0. Comparing with > keeps the first of tied values and >= the last.

What is the two-pointer technique?

Two indices move through an array together, usually from both ends toward each other in a while (lo < hi) loop, to check palindromes, find a pair with a given sum in sorted data or reverse in place. Moving them in the same direction at different speeds removes duplicates.

What is the sliding window technique?

A sliding window keeps a running result over a fixed-length run of elements in one pass: add the element entering the window and subtract the one leaving it, instead of re-summing every window. It finds the best sum of k consecutive elements in linear time.

How do I loop over every pair of elements once?

Nest two loops and start the inner one at i + 1: for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++). That visits each unordered pair exactly once, never pairing an element with itself; starting j at 0 gives ordered pairs, self-pairs included.

Why do all and any loops start with true and false?

An all-check assumes every element passes and hunts for a counterexample, so it starts true and becomes false at the first failure; an any-check starts false and hunts for a single witness. Both can stop early, and on an empty input all is true and any is false.

Exercises

Four patterns, one pass each

Read integers n and k (1 ≤ k ≤ n), then n integers. Print four lines:

  1. max=<largest value> at=<index of its FIRST occurrence>
  2. run=<length of the longest non-decreasing run> (consecutive elements where each is ≥ the previous)
  3. window=<largest sum of k consecutive elements>
  4. allPositive=<true|false>

Seed the max from the first element, not from 0.

Example: 6 2 then 3 -1 4 4 5 2 →

max=5 at=4
run=4
window=9
allPositive=false

Runs, searches and thresholds

Read an integer n, n integers, and a threshold t. Print three lines, each one loop pattern:

  • run: value <v> length <k> — the longest run of equal adjacent values (the first such run on ties).
  • firstNegative: <index or -1> — a search with early exit.
  • untilOver: <k> — how many elements, from the start, are needed before the running sum exceeds t (n if it never does).

Example: 7 then 3 3 -1 5 5 5 2 then 10 →

run: value 5 length 3
firstNegative: 2
untilOver: 5

In this module: Control flow

← break, continue, labels and return · Checkpoint — Control flow →