Problem overview
The function count takes a vector of integers, nums, and an integer value. It returns how many times value appears in nums.
For nums = [1, 4, 2, 2, 5, 2] and value = 2, the 2 appears at three positions, so the result is 3. If the value does not appear at all, the result is 0.
The task is to write the loop yourself and not to rely on a ready-made helper. This is the counting pattern, which shows up in many later problems.
Approach
Look at every element once. Keep a counter that starts at 0, and each time an element equals value, add 1 to it. After the last element, the counter is the answer.
Elements that differ from value are skipped. The order of the elements does not matter, and neither does what the other values are, so there is no need to sort or to remember anything beyond the counter.
On the example, the counter goes 0, then stays at 0 for 1 and 4, rises to 1 at the first 2, rises to 2 at the second, stays at 2 for 5, and reaches 3 at the last 2.
Step by step
- Declare the counter.
let mut count = 0;creates it as mutable, because it changes inside the loop. Withoutmut,count += 1would not compile. - Loop over a reference to the vector.
for n in &numsborrows the vector. Looping overnumsdirectly would move the vector into the loop. - Compare with
value. Iterating by reference givesnthe type&i32. Rust does not compare a&i32with ani32, so the condition writes*n == value, where*nreads the number behind the reference. - Increment on a match. Inside the
if,count += 1adds one. Rust has no++operator. - Return after the loop. The
returngoes outside the loop, so it runs only after every element has been checked.
The solution in Rust
impl Solution {
fn count(nums: Vec<i32>, value: i32) -> i32 {
let mut count = 0;
for n in &nums {
if *n == value {
count += 1;
}
}
return count;
}
}
Some Rust details here:
- References and
*.&numsis a borrowed view of the vector, and iterating over it yields references to the elements. The dereference*nturns a&i32back into ani32for comparison. - Why borrowing is useful. A
forloop overnumswould consume the vector. Here the function ownsnumsanyway and nothing uses it afterwards, so either would compile, but borrowing is the habit that carries over to functions that need the vector later. - Same name for variable and function. The local
counthas the same name as the methodcount. This is legal, because the function is always reached throughSolution::countand never by the bare namecount, so the variable does not hide it. - Type inference. The compiler makes
countani32, since the function returnsi32. - No
++. Usecount += 1.
Complexity
Time: O(n). Each of the n elements is compared once. Skipping or counting an element takes constant time.
Space: O(1). The function keeps only the counter and the loop variable.
Edge cases and common mistakes
- An empty vector. The loop does not run, and the result is 0.
- A value that never appears. The counter stays at 0.
count(vec![1, 1], 3)returns 0. - A vector made only of the value.
count(vec![2, 2, 2], 2)returns 3. - Returning inside the loop. A
return count;placed in the loop body would end the function after the first element. - Setting instead of adding. Writing
count = 1;in theifrecords only that the value was seen, not how many times. - Comparing a reference with a number.
n == valuefails to compile, because&i32andi32are different types. Dereference with*n.
Testing
nums = [1, 4, 2, 2, 5, 2],value = 2gives 3.nums = [],value = 2gives 0.nums = [1, 1],value = 3gives 0.nums = [7],value = 7gives 1.
