Problem overview
minAndMax(nums) receives an array of integers with at least one number. It returns the smallest and the largest number together, as an array of two values with the smallest first. For [4, -2, 9, 0] the answer is [-2, 9]. For a one-number array such as [7] the number is both, so the answer is [7, 7]. For [-5, -1, -8] it is [-8, -1].
The statement asks for one loop and no built-in min or max.
Approach
Keep two variables, low and high, that always hold the smallest and largest numbers seen so far. Look at each number once. If it is below low, it becomes the new low; if it is above high, it becomes the new high.
Both start at nums[0]. Starting at 0 would be wrong: if every number is above 0, a starting low of 0 would never be replaced, and if every number is below 0, high would stay at 0. The first number is always a real candidate.
Step by step
- Declare
lowandhighwithlet, both set tonums[0]. - Loop over the array with
for...of. - Inside the loop, an
iflowerslowwhennumis smaller. - A second, separate
ifraiseshighwhennumis larger. It is not anelse: with one number, both checks are false and nothing changes, which is correct. - After the loop, return
[low, high].
The solution in JavaScript
class Solution {
minAndMax(nums) {
let low = nums[0];
let high = nums[0];
for (let num of nums) {
if (num < low) {
low = num;
}
if (num > high) {
high = num;
}
}
return [low, high];
}
}
JavaScript has no tuple type, so an array of two values is how a function returns a pair. The caller can unpack it with const [lo, hi] = .... Running the three examples gives:
[-2, 9]
[7, 7]
[-8, -1]
Tracing the first example
For [4, -2, 9, 0], low and high both start at 4. After each number they hold:
num=4 low=4 high=4
num=-2 low=-2 high=4
num=9 low=-2 high=9
num=0 low=-2 high=9
The loop looks at 4 first, even though it is also the starting value. That extra pass changes nothing, and it keeps the loop simple. The last number, 0, is neither smaller than -2 nor larger than 9, so both variables stay as they are.
Complexity
The loop visits each number once and does two comparisons, so the time is O(n). The two variables and the returned pair take a fixed amount of memory, so the extra space is O(1). Finding the smallest and then the largest in two separate loops would also be O(n), but it reads the array twice.
Edge cases and common mistakes
- Starting at 0. For
[5, 2, 8]the right answer is[2, 8], but a version that starts both variables at 0 returns[0, 8]. - Using
else iffor the second check. Withnums[0]as the start this happens to work for most inputs, but two independentifs are simpler to reason about. - Returning
[high, low]. The smallest comes first. The tests compare the pair in order, so the right numbers in the wrong order still fail. - Reaching for
Math.min(...nums). It is handy in real code, but this lesson asks for the loop.
