Home/Data structures & algorithms/Arrays and linear scans

Arrays and linear scans

Accumulators, indices, and loop invariants

A monitoring job receives request counts in minute order. The report needs the total traffic and the first minute with the highest count. Sorting the readings would do extra work and make the original positions harder to track; storing the whole stream isn't necessary either.

If the busiest value appears again later, the report should still point to its first occurrence. That small requirement decides which comparison belongs in the loop.

Keeping the first busiest minute

Keep the running total and a candidate peak position. Replace the position only for a strictly larger reading; an equal later peak keeps the earlier position. The first reading establishes a candidate, while an empty input never does. This distinguishes an empty report from a real zero-traffic minute.

Summarising the stream once

For readings [6, 2, 6], the total moves through 6, 8, and 14. The busiest position stays at 0: the last reading ties rather than improves the peak. After every step, the retained information describes exactly the prefix already consumed. An empty stream has a total of zero and no busiest position; zero traffic is a real reading, not a missing value.

go
readings := []int{6, 2, 6}
total := 0
var first *int
for index, value := range readings {
	total += value
	if first == nil || value > readings[*first] {
		saved := index
		first = &saved
	}
}
fmt.Println(total, *first) // 14 0; this example is nonempty.

When another pass costs more

A useful invariant states exactly what a summary knows about the consumed prefix. A strict improvement updates the first maximum; an equal value must keep the earlier index. Starting an extremum at zero would be wrong for a broader signed-input contract. A constant number of linear passes is still O(n), while sorting performs unnecessary ordering work. Real uses include request-size summaries and sensor aggregates; repeated range queries call for preprocessing instead.

A scan takes O(n) arithmetic operations and a fixed number of summary values. Separate total, maximum, and first-position scans are also O(n); combining them saves traversals and supports a one-pass input. Sorting first adds O(n log n) work without improving this report.

The monitoring job can emit its total and peak position as soon as the final reading arrives.

Practice Arrays and linear scans

Implement the exercise in a full-screen workspace, then run its tests.

Open practice
Next lessonStrings and frequency maps