Start learning free

LESSON 268 OF 679 · TUPLES, SORTING & BUILT-INS

Min and Max in Rust: Both in One Loop, Returned as a Tuple

Practice Read the full explanation

You get a Vec of integers nums. Return its smallest and its largest number together, as a pair.

The smallest number comes first. The function's return type shows how your language holds the pair.

Find both in one loop. Don't use a built-in min or max function.

 

Example 1:

Input: nums = [4, -2, 9, 0]
Output: (-2, 9)
Explanation: The smallest number is -2.
The largest number is 9.

Example 2:

Input: nums = [7]
Output: (7, 7)
Explanation: The only number is both the smallest and the largest.

Example 3:

Input: nums = [-5, -1, -8]
Output: (-8, -1)
Explanation: All the numbers are below 0.
The smallest is -8, and the largest is -1.

 

Constraints:

  • nums has at least one number.
  • Every number is between -106 and 106.
STEP 1 OF 5
    Ctrl + Enter to check

    RUST · TUPLES, SORTING & BUILT-INS

    Min And Max in Rust, explained

    Problem overview

    The function min_and_max receives a vector of integers, nums, which always holds at least one number. It returns the smallest and the largest number together as a tuple (i32, i32), smallest first. The lesson asks for one loop and no built-in min or max.

    For [4, -2, 9, 0] the answer is (-2, 9). For [7] it is (7, 7), because the only number is both the smallest and the largest. For [-5, -1, -8] it is (-8, -1).

    Approach

    Keep two running answers, low and high, and compare every number with both. After one pass, low holds the smallest number seen and high the largest.

    The starting values matter. Starting both at 0 would be wrong when every number is above 0 (the low would stay 0) or every number is below 0 (the high would stay 0). The first number is always a real candidate, so both start at nums[0]. That is safe because the vector is never empty; on an empty vector, nums[0] would panic.

    The two answers are independent. A number can change low, change high, or change neither, and the first number cannot change either, because it already is both.

    Step by step

    1. Declare low and high with let mut, both set to nums[0]. They need mut because the loop will change them.
    2. Loop over &nums. Borrowing the vector leaves it usable after the loop. The loop variable num is a reference to a number.
    3. Update low. If *num is smaller than low, store it. The * reads the number that the reference points to.
    4. Update high. If *num is larger than high, store it. This is a separate if, so each number is checked against both running answers.
    5. Return (low, high) after the loop, smallest first.

    The solution in Rust

    impl Solution {
        fn min_and_max(nums: Vec<i32>) -> (i32, i32) {
            let mut low = nums[0];
            let mut high = nums[0];
            for num in &nums {
                if *num < low {
                    low = *num;
                }
                if *num > high {
                    high = *num;
                }
            }
            return (low, high);
        }
    }

    The function returns a tuple, which is how a Rust function hands back two values at once. Comparing *num with low works because both are i32; writing num < low would compare a reference with a number, and the compiler reports mismatched types.

    The loop reads each number once, so the time grows in step with the length of the vector, and the function stores just two extra numbers however long the vector is. Rust's iterators also have ready-made min() and max() methods, but this lesson asks you to write the comparison yourself, which shows what those methods do inside.

    Following the loop

    For nums = [4, -2, 9, 0], these are the values of low and high after each number is checked:

    numlowhigh
    444
    -2-24
    9-29
    0-29

    Sorting the vector and taking its first and last numbers would also work, but it does more work than this single pass needs.

    Testing

    Running the function on the three examples prints:

    (-2, 9)
    (7, 7)
    (-8, -1)

    Edge cases and common mistakes

    • Starting at 0. It fails on all-positive and all-negative vectors, as in the third example.
    • Forgetting the *. num is a reference, so comparing or storing it without * gives a type error.
    • One number. Both answers stay at that number, which is why a single value gives (7, 7).
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free