Problem overview
The function drop_ends receives a vector of integers, nums, with at least two numbers. It returns a new vector with every number except the first and the last, keeping the order of those in between. When there are exactly two numbers, nothing lies between the ends, so the result is empty.
For [4, 8, 15, 16, 23] the ends are 4 and 23, so the answer is [8, 15, 16]. For [9, 0, 9] both 9s are ends and only the 0 remains.
Approach
Index 0 is the first number and index nums.len() - 1 is the last. The numbers worth keeping are at indexes 1 through len - 2. A range 1..nums.len() - 1 expresses that exactly, because a Rust range includes its start and leaves out its end. So the start of 1 skips the first number, and the end of len - 1 skips the last one.
Step by step
- Build the range
1..nums.len() - 1and slicenumswith it. For five numbers that is1..4, which covers indexes 1, 2 and 3. - Copy the slice into an owned vector with
to_vec(), and store it inmiddle. A bare slice only borrows fromnums, so it can't be returned as aVec. - End the function with
middle, without a semicolon, so Rust returns it.
The solution in Rust
impl Solution {
fn drop_ends(nums: Vec<i32>) -> Vec<i32> {
let middle = nums[1..nums.len() - 1].to_vec();
middle
}
}
With exactly two numbers the range is 1..1, which is empty, so middle is an empty vector and no special case is needed. The expression nums.len() - 1 is a usize, and it is safe here only because the constraints promise at least two numbers.
Following one call
For nums = [4, 8, 15, 16, 23], the length is 5, so the range is 1..4. It selects the items at indexes 1, 2 and 3, which are 8, 15 and 16. Index 0 (the 4) and index 4 (the 23) are never part of it. The input vector is not changed; the function copies the middle part into a new vector and returns that. Thinking in terms of the range's two ends makes the code easy to check: the start says how many items to skip at the front, and the distance from the end of the range to the length says how many to skip at the back.
Edge cases and common mistakes
- A vector with fewer than two numbers. With one number, the range becomes
1..0, and Rust panics with "slice index starts at 1 but ends at 0". With an empty vector,nums.len() - 1would underflow the unsigned length (a panic in a debug build, a wrapped huge number in an optimized one). The lesson rules both out. - Using
1..nums.len(). That drops only the first number and keeps the last. - Using
0..nums.len() - 1. That drops only the last number and keeps the first.
Testing
Results from running the function:
[4, 8, 15, 16, 23]gives[8, 15, 16].[9, 0, 9]gives[0].[1, 2]gives[].
