Problem overview
The function max_sum_subarray receives a vector nums of integers that may be positive, negative or zero. It returns the largest sum that a continuous run of elements can have. A continuous run, a subarray, is a slice of the vector: elements next to each other, with no gaps, and at least one element.
For nums = [-2, -5, 6, -2, -3, 1, 5, -6] the answer is 7, from the subarray [6, -2, -3, 1, 5]: 6 - 2 - 3 + 1 + 5 = 7. No other run does better. The statement allows O(n²) time and O(1) extra space.
Approach: try every subarray, but reuse the running sum
A subarray is fixed by its first index i and its last index j, with i <= j. Brute force tries every such pair and keeps the best sum.
The cost depends on how each sum is computed. Adding up nums[i..=j] from scratch for every pair makes the algorithm O(n³). A prefix-sum array would give each sum in constant time, but it needs O(n) extra space, which the statement doesn't allow.
There is a cheaper trick. For a fixed i, move j to the right one step at a time. The subarray from i to j is the previous one plus the single element nums[j]. So one variable, sum, can carry the sum along: reset it to 0 when i changes, and add nums[j] each time j advances. Every pair then costs O(1), which gives O(n²) overall and a few integers of memory.
On the example with i = 2, sum runs through 6, 4, 1, 2, 7 as j goes from 2 to 6. The last value, 7, is the best so far, so max_sum becomes 7.
Step by step
- Declare
max_sumwithlet mutand start it atnums[0]. Starting at 0 would be wrong when every number is negative, because the answer is then negative and 0 would beat it.nums[0]is a real subarray sum, so it is a safe starting point. - Loop over the first index:
for i in 0..nums.len(). The range stops beforenums.len(), so it covers exactly the valid indices. - Declare
suminside that loop, starting at0i32. Declaring it there resets it for each newi. Thei32suffix pins the type of the literal. - Loop over the last index:
for j in i..nums.len(). Starting atikeepsj >= iand includes one-element subarrays. - Add
nums[j]tosum. Nowsumequals the sum ofnums[i..=j]. - Compare with
max_sum. Ifsumis greater, store it. - Return
max_sumas the last expression, with no semicolon, after both loops finish.
The solution in Rust
impl Solution {
fn max_sum_subarray(nums: Vec<i32>) -> i32 {
let mut max_sum = nums[0];
for i in 0..nums.len() {
let mut sum = 0i32;
for j in i..nums.len() {
sum += nums[j];
if sum > max_sum {
max_sum = sum;
}
}
}
max_sum
}
}
The Rust details in this code:
- Ranges are half-open.
0..nums.len()includes 0 and excludesnums.len(). To include the end, you would write0..=n. The loop variablesiandjareusize, the type Rust requires for indexing. - The last line is the return value.
max_sumhas no semicolon, so it is the value of the block and therefore of the function. Adding a semicolon would turn it into a statement, and the function would fail to compile because it would produce()instead of ani32. let mut sum = 0i32;is the same aslet mut sum: i32 = 0;. The variable ismutbecause+=changes it.- Indexing is bounds-checked.
nums[j]panics whenjis out of range instead of reading stray memory. The loop ranges guarantee it never is. - Overflow wraps in optimized builds. The lessons build with
-O, wheresum += nums[j]wraps around silently if the total leaves thei32range. A debug build would panic instead.
Complexity
Time: O(n²). For i = 0 the inner loop runs n times, for i = 1 it runs n - 1 times, and so on down to 1. That is n(n + 1)/2 steps, each of constant cost.
Space: O(1). The code keeps max_sum, sum and the two loop counters. It never copies or slices the input.
Edge cases and common mistakes
- All negative numbers. For
[-3, -1, -2]the answer is-1, the best single element. The subarray must have at least one element, so the answer can't be 0. - A single element. For
[5]the loops run once and the answer is5. - All positive numbers. The best subarray is the whole vector:
[1, 2, 3]gives6. - Resetting
sumin the wrong place. Ifsumis declared before the outer loop, it keeps its value across different values ofi, and later subarrays include elements from earlier ones. Declare it inside the outer loop. - Starting
jat 0. The inner loop must start ati, otherwise the code sums runs that begin before the chosen first index. - Overflow. For
[1500000000, 1500000000]the true answer is 3,000,000,000, which doesn't fit in ani32. In an optimized build the sum wraps to a negative number, and the function returns1500000000. Tests with huge values would needi64. - Empty input.
nums[0]panics on an empty vector. The lesson's inputs have at least one element.
Testing
[-2, -5, 6, -2, -3, 1, 5, -6]gives7.[-3, -1, -2]gives-1.[5]gives5.[1, 2, 3]gives6.[-2, 1, -3, 4, -1, 2, 1, -5, 4]gives6.
