Problem overview
The function max_val_num_of_occurrences takes a vector of integers, nums, and returns a vector of two numbers: the largest value in nums, then the number of times that value appears.
For nums = [2, 7, 11, 8, 11, 8, 3, 11] the largest value is 11, and it appears three times, so the answer is [11, 3]. Note that 8 also appears twice, but only the maximum counts.
The statement asks for O(n) time and O(1) extra space, and the follow-up asks whether the array can be read only once.
Approach: track the maximum and its count together
The simple plan uses two loops over the vector. The first finds the maximum, the second counts how many elements equal it. That is already O(n), since two passes cost 2n steps, which is still linear. The one-pass version does both jobs at once by updating two variables, max_val and count, as each element arrives. For every element value there are three cases:
value > max_val: a new maximum. Store it and resetcountto 1, because the old count described a smaller value.value == max_val: one more copy of the current maximum, so add 1 tocount.value < max_val: it can't matter, so do nothing.
Here is the trace for [2, 7, 11, 8, 11]. max_val starts at 2 with count 0. The first element, 2, equals max_val, so count becomes 1. Then 7 is larger: max_val = 7, count = 1. Then 11 is larger: max_val = 11, count = 1. The 8 is ignored, and the second 11 raises count to 2.
Why does the reset matter? Take [2, 2, 5]. After the two 2s, count is 2, but that is the count of the value 2. Once 5 arrives, the maximum changes, and the old count describes a different number. Setting it back to 1 keeps count always tied to the current max_val. This invariant is the whole idea of the one-pass solution: at every moment, count is the number of times max_val appears among the elements seen so far.
Step by step
- Declare
max_valandcountwithlet mut.max_valstarts atnums[0], a value that really is in the array, which keeps the answer right when every number is negative.countstarts at 0 because the loop visitsnums[0]again and counts it through the equal case. - Loop over
numswith a variable namedvalue. - Test
value > max_val. It must be a strict comparison, because an equal value is another occurrence, not a new maximum. - Update both variables in that branch:
max_valbecomesvalue, andcountis reset to 1. - Add the
else if value == max_valbranch and incrementcountwith+=. Rust has no++operator. - Return both numbers in a vector built with
vec!.
The solution in Rust
impl Solution {
fn max_val_num_of_occurrences(nums: Vec<i32>) -> Vec<i32> {
let mut max_val = nums[0];
let mut count = 0;
for value in nums {
if value > max_val {
max_val = value;
count = 1;
} else if value == max_val {
count += 1;
}
}
return vec![max_val, count];
}
}
The Rust details worth knowing:
- The type of
countis inferred. Nothing says what type0is. The compiler sees thatcountgoes into aVecalongside thei32max_val, and choosesi32. for value in numsmoves the vector. The loop takes ownership ofnums, and the vector can't be used afterwards. Usingnums.len()after the loop fails with "borrow of moved value". Herenums[0]is read before the loop, and nothing needs the vector later. To keep it, loop over&numsinstead, which makesvaluea reference of type&i32. The comparisons then need a dereference, as in*value > max_val, because Rust doesn't compare an&i32with ani32.nums[0]copies ani32. Integers implementCopy, so reading an element leaves the vector intact.- No parentheses around conditions, and
else ifis written on the same line as the closing brace. vec![max_val, count]builds the result vector. Both items must have the same type, which is whycountis ani32.
Complexity
Time: O(n). The loop visits each element once and does constant work for each: a comparison and at most one or two assignments.
Space: O(1). The function stores two integers. The result vector always has two entries, no matter how long nums is.
Edge cases and common mistakes
- Empty input.
nums[0]panics with "index out of bounds: the len is 0 but the index is 0". The lesson's input always has at least one element. - All negative numbers. For
[-5, -5, -9]the answer is[-5, 2]. Startingmax_valat 0 would return 0 with a count of 0. - Single element. For
[4]the loop sees 4 equal tomax_val, so the answer is[4, 1]. - Forgetting the reset. If
countisn't set back to 1 when a new maximum appears, the occurrences of smaller values leak into the answer. For[2, 2, 5]the count of 2 survives and the result is[5, 2]instead of[5, 1]. - Resetting to 0 instead of 1. The new maximum was just seen, so it already counts once. With 0,
[2, 2, 5]would give[5, 0]. - Starting
countat 1. Since the loop also visitsnums[0], the first element would be counted twice.
Testing
[2, 7, 11, 8, 11, 8, 3, 11]gives[11, 3].[-5, -5, -9]gives[-5, 2].[4]gives[4, 1].[2, 2, 5]gives[5, 1].[9, 1, 9, 9]gives[9, 3].
