Problem overview
The function odd_even receives a vector of integers, numbers, and returns a bool: true if the vector holds more odd numbers than even numbers, and false otherwise. A tie, including an empty vector, gives false.
For [1, 2, 3, 4, 5, 6, 7, 8, 9] there are five odd numbers (1, 3, 5, 7, 9) and four even ones (2, 4, 6, 8). Five is greater than four, so the answer is true.
Approach: two counters and one comparison
You need two numbers: how many odd values there are and how many even ones. Count both in a single pass. Each element is either odd or even, so every iteration increases exactly one of the two counters. After the loop, one comparison gives the answer.
To classify a number, use the remainder operator %. An even number leaves remainder 0 when divided by 2, and an odd number doesn't.
Here is the idea on [4, 7, 10, 3, 9]. The counters start at 0 and 0. The value 4 is even, so the counters become 0 and 1. The value 7 is odd (1 and 1), 10 is even (1 and 2), 3 is odd (2 and 2) and 9 is odd (3 and 2). The loop ends with three odd numbers against two even ones, so the function returns true.
You could also keep a single counter that goes up for an odd number and down for an even one, and return whether it ends above zero. Two counters are easier to read and to debug, and they cost almost nothing, so this lesson uses them.
Step by step
- Declare
odd_numbersandeven_numberswithlet mut, both starting at0. They needmutbecause the loop increments them, and without it the compiler rejects+=. - Write a
forloop overnumberswith the loop variablenumber. It visits every element in order. - Test for odd. Inside the loop, check
number % 2 != 0and incrementodd_numbersin that branch. The check is "not 0" rather than "equal to 1" for a reason covered below. - Add the
elsebranch for even numbers and incrementeven_numbersthere. - Return the comparison.
odd_numbers > even_numbersis already abool, so the function returns it directly instead of wrapping it in anifthat returnstrueorfalse.
The solution in Rust
impl Solution {
fn odd_even(numbers: Vec<i32>) -> bool {
let mut odd_numbers = 0;
let mut even_numbers = 0;
for number in numbers {
if number % 2 != 0 {
odd_numbers += 1;
} else {
even_numbers += 1;
}
}
return odd_numbers > even_numbers;
}
}
The Rust details worth a closer look:
- The sign of
%. In Rust, the result of%takes the sign of the left operand. So3 % 2is1, but-3 % 2is-1. A test likenumber % 2 == 1would count -3 as even. Comparing with!= 0works for both signs. Rust also hasrem_euclid, which never returns a negative remainder:(-3i32).rem_euclid(2)is1. - Inferred counter types. The counters start as a bare
0, and Rust picks a type for them. Nothing else constrains them here, so they default toi32. Comparing them with each other is fine because both have the same type. - Looping by value.
for number in numbersmoves the vector into the loop, and eachnumberis ani32rather than a reference, so no dereferencing is needed. The function ownsnumbersand doesn't use it afterwards, so moving it is fine. if/elseas the only two cases. Because every integer is either odd or even, theelsebranch needs no condition of its own.
Complexity
Let n be the number of elements.
Time: O(n). One pass over the vector, with a constant amount of work per element.
Space: O(1). Two counters, whatever the length of the vector.
Edge cases and common mistakes
- Negative numbers.
[-1, -3, 2]has two odd values and one even, so the answer istrue. With the== 1test, both negative odds would fall into the even count and the answer would befalse. - Ties.
[1, 2]has one of each, so the answer isfalse. The comparison is strict: "more than", not "at least as many as". - Empty vector. Both counters stay 0, 0 is not greater than 0, and the result is
false. - Zero. 0 is even, since
0 % 2is 0, so it adds to the even count like any other even number. A vector of only zeros returnsfalse. - Extreme values.
i32::MAX(2147483647) is odd andi32::MIN(-2147483648) is even. The remainder by 2 gives the right class for both, because the check never adds or multiplies the number, so nothing can overflow. - Forgetting
mut. The counters can't be incremented without it. - Returning inside the loop. The answer is known only after all elements are counted, so the comparison goes after the loop.
Testing
[1, 2, 3, 4, 5, 6, 7, 8, 9]givestrue.[-1, -3, 2]givestrue.[1, 2]givesfalse.[]givesfalse.
