Problem overview
The method oddEven receives an array of integers, numbers. It returns true if the array holds more odd numbers than even numbers, and false otherwise. A tie returns false, because "more" means strictly more.
In the example Array(1, 2, 3, 4, 5, 6, 7, 8, 9) there are five odd numbers (1, 3, 5, 7, 9) and four even numbers (2, 4, 6, 8). Five is greater than four, so the result is true.
Approach: two counters and one comparison
The method needs two totals: how many odd numbers and how many even numbers it has seen. Walk through the array once. For each element, decide whether it is odd or even and increase the matching counter. When the walk is finished, compare the two counters and return whether the odd one is bigger.
You don't need the numbers themselves afterwards, only the two counts. Because every integer is either odd or even, a single if with an else covers every element.
For the example, the two counters change like this as the loop moves along:
number | Odd? | oddNumbers | evenNumbers |
|---|---|---|---|
| 1 | yes | 1 | 0 |
| 2 | no | 1 | 1 |
| 3 | yes | 2 | 1 |
| 4 | no | 2 | 2 |
| 5 to 9 | odd, even, odd, even, odd | 5 | 4 |
A first idea might be to copy the odd numbers into one array and the even numbers into another, and compare their lengths. That works but allocates memory that grows with the input, while counters need none. Since only the sizes matter, counting is enough.
Step by step
- Declare
oddNumbersandevenNumberswithvar, both 0. Each goes on its own line. They change in the loop, so they can't beval. Scala infersIntfrom the literal. - Loop with
for (number <- numbers). The body runs once for each element, withnumberholding the current one. - Test oddness with
number % 2 != 0and add 1 tooddNumberswhen it holds. The next section explains why the test is "not 0" and not "equals 1". Scala has no++, so the increment is+= 1. - Add an
elsebranch that incrementsevenNumbers. It runs exactly when the condition is false, which means the remainder was 0. - Return
oddNumbers > evenNumbers. A comparison is already aBoolean, so it can be returned directly without anif.
The solution in Scala
class Solution {
def oddEven(numbers: Array[Int]): Boolean = {
var oddNumbers = 0
var evenNumbers = 0
for (number <- numbers) {
if (number % 2 != 0) {
oddNumbers += 1
} else {
evenNumbers += 1
}
}
return oddNumbers > evenNumbers
}
}
Why != 0 and not == 1
The remainder operator % in Scala takes the sign of the left operand. For positive numbers that gives the familiar results: 3 % 2 is 1 and 4 % 2 is 0. For negative numbers the remainder of an odd value is -1:
3 % 2 // 1
-3 % 2 // -1
-4 % 2 // 0
A test written as number % 2 == 1 would treat -3 as not odd, and count it as even. The test number % 2 != 0 works for both signs, because every odd number, positive or negative, has a nonzero remainder. For Array(-3, -5, 2) the correct method returns true, since two of the three numbers are odd.
Other details
- The loop variable
numberis read-only inside the body. - The parentheses around
for (number <- numbers)hold a generator. The arrow reads "for eachnumberinnumbers". - Another way to ask whether an
Intis odd is the bitwise test(number & 1) != 0, which also works for negative values. The remainder test is easier to read for most learners. - Returning a comparison directly is shorter than
if (...) true else falseand means the same.
A single counter
The question only asks which count is larger, so one variable can do the job of two. Add 1 for an odd number and subtract 1 for an even one, and return whether the balance ends above 0:
var balance = 0
for (number <- numbers) {
if (number % 2 != 0) balance += 1 else balance -= 1
}
balance > 0
This gives the same results as the two-counter version on every input: true for the example and for Array(-3, -5, 2), false for a tie and for an empty array. The two-counter version is easier to read, and it is the one the lesson asks for.
Complexity
One pass over n numbers with constant work for each gives O(n) time. The method stores two counters and the loop variable, so the extra space is O(1).
Edge cases and common mistakes
- A tie. With the same number of odd and even values, such as
Array(1, 2), the result isfalse. Writing>=would be a bug. - An empty array. Both counters stay 0, 0 is not greater than 0, and the result is
false. - Negative numbers. Test with
!= 0, as above. - Zero. It is even, since
0 % 2is 0, so it incrementsevenNumbers. - Extreme values.
Int.MaxValue(2147483647) is odd and its remainder is 1.Int.MinValue(-2147483648) is even and its remainder is 0. The test needs no special care at either end of the range. - Swapped counters. If the odd branch increments
evenNumbersby mistake, the method answers the opposite question for every input. Tracing the example by hand, as in the table above, catches this at once. - Returning the counts. The method returns a
Boolean, not a number.
Testing
Try Array(1, 2, 3, 4, 5, 6, 7, 8, 9) (true), Array(-3, -5, 2) (true), Array(1, 2) (false) and an empty array (false).
