Problem overview
The function max_sum receives a vector of integers, nums, and a positive integer k. Among all contiguous subarrays of length exactly k, it finds the one with the largest sum and returns its first and last index as a vector of two i32 values.
For nums = [5, 6, 1, 2, 6, 6, 4, 3] and k = 3, the window at indices 4 to 6 holds 6, 6 and 4, with sum 16. That is the largest, so the function returns [4, 6].
Approach: slide the window instead of re-adding it
The straightforward method sums every window from scratch, which costs k additions for each of the n - k + 1 windows, or O(n * k) in all. But two neighbouring windows share k - 1 elements. The window starting at i is the previous window with one element removed on the left, nums[i - 1], and one added on the right, nums[i + k - 1].
So the sum needs only one subtraction and one addition to move one step. Compute the first window's sum once, then update it as the window slides across the vector. Every window gets its sum in constant time, and the whole scan is O(n).
On the example, the first window [5, 6, 1] sums to 12. Moving right removes 5 and adds 2, giving 9. Then it removes 6 and adds 6, giving 9. Next it removes 1 and adds 6 for 14, then removes 2 and adds 4 for 16, and finally removes 6 and adds 3 for 13. The best, 16, was reached when the window started at index 4.
The same trick works whenever a window has a fixed size and its value can be updated by removing one element and adding another: sums, counts and similar totals. It doesn't depend on the values being positive, so negative numbers need no special handling.
Step by step
- Sum the first window. The slice
nums[..k]holds the firstkelements, anditer().sum()adds them. The variablesumis an annotatedi32and is declaredmut, because it will change as the window moves. - Set
besttosum. The first window is the best one seen so far. No sentinel value is needed. - Set
answerto the first window's bounds,0andk - 1, asi32values. If no later window beats it, this is the result. - Loop over the remaining starts, with
ifrom 1 ton - kinclusive. - Slide the window. Subtract the element that just left,
nums[i - 1], and add the one that just entered,nums[i + k - 1]. - Compare. If
sumis greater thanbest, update bothbestandanswer. The strict comparison keeps the earliest window when two have equal sums. - Return
answeras the tail expression.
The solution in Rust
impl Solution {
fn max_sum(nums: Vec<i32>, k: i32) -> Vec<i32> {
let k = k as usize;
let n = nums.len();
let mut sum: i32 = nums[..k].iter().sum();
let mut best = sum;
let mut answer = vec![0i32, k as i32 - 1];
for i in 1..=(n - k) {
sum = sum - nums[i - 1] + nums[i + k - 1];
if sum > best {
best = sum;
answer = vec![i as i32, (i + k - 1) as i32];
}
}
answer
}
}
The Rust details worth a closer look:
- Shadowing.
let k = k as usize;creates a newkof typeusizethat hides thei32parameter, so it can be used in slices and index arithmetic. - Open-ended slice.
nums[..k]is shorthand fornums[0..k]. It excludes indexk, so it has exactlykelements. - Why
sumis annotated.iter().sum()can produce several numeric types, so the compiler needs: i32to know which one to build. - The empty range. When
kequalsn, the loop range1..=0is empty and the body never runs, so the answer is the first window. - Cast precedence.
k as i32 - 1means(k as i32) - 1. The index arithmetici + k - 1is done inusizeand cast afterwards. - A
klarger than the vector. The slicenums[..k]panics with an out-of-range message. The lesson assumeskis at most the length ofnums. - Overflow. The running
sumis ani32. In the optimized build, a window total beyond thei32range wraps silently; a debug build panics.
Complexity
Time: O(n). The first window costs k additions and each of the other n - k windows costs two operations. Each element enters the window once and leaves it once.
Space: O(1). The slice is a borrowed view, and only a few integers and the two-element answer are stored.
Edge cases and common mistakes
kequals the length. There is a single window, and the example withk = 8returns[0, 7].k = 1. Each element is a window. The example returns[1, 1], the first 6.- Ties. For
[1, 3, 2, 2, 3, 1]withk = 2, the windows at 1 and 3 both sum to 5, and the answer is[1, 2]. A>=comparison would move it to the later window,[3, 4]. - Negative values.
[-5, -2, -7, -1]withk = 2gives[0, 1], a sum of -7. Becausebeststarts from the first window rather than 0, negative sums work. - Wrong entering index. The element that enters is
nums[i + k - 1], the last element of the new window. Usingnums[i + k]reads one element too far and panics on the final window. - Forgetting to subtract. Adding the new element without removing the old one turns the window into a growing prefix.
Testing
[5, 6, 1, 2, 6, 6, 4, 3]withk = 3gives[4, 6].- The same vector with
k = 8gives[0, 7]. - The same vector with
k = 1gives[1, 1]. [1, 3, 2, 2, 3, 1]withk = 2gives[1, 2].[-5, -2, -7, -1]withk = 2gives[0, 1].
