Problem overview
The function maxSum receives a slice of integers, nums, and a positive integer k. It returns the first and last index of the contiguous block of exactly k elements with the largest sum, as a two-element slice.
For nums = [5, 6, 1, 2, 6, 6, 4, 3] and k = 3, the block at indices 4 to 6 (6, 6, 4) adds up to 16, the largest of all windows, so the answer is [4 6].
Approach: slide the window
The brute force adds up k elements for every window, which costs O(n * k). But two neighbouring windows share k - 1 elements. Moving from the window that starts at i - 1 to the one that starts at i drops exactly one element, nums[i-1], and adds exactly one, nums[i+k-1]. So each new sum is the old sum minus one value plus another, in constant time.
The plan is to compute the first window's sum once with k additions, then slide across the rest of the slice with one subtraction and one addition per step. The total is O(n).
Step by step
- Start
answerwith the first window,[]int{0, k - 1}. If no later window is better, this is the result, so an empty starting value would be wrong. - Declare
sumas 0. It will always hold the sum of the current window. - Add the first
kelements with a loop over indices 0 tok - 1. Nowsumis the first window's sum. - Declare
maxSumand set it tosum. The first window is the best one seen so far. - Loop over the remaining starts,
ifrom 1 tolen(nums)-kinclusive. The last window starts atlen(nums)-k, so the condition uses<=. - Slide. Subtract
nums[i-1], the element that just left the window, and addnums[i+k-1], the one that just entered. - Compare. If
sumis strictly greater thanmaxSum, updatemaxSumand setanswerto[]int{i, i + k - 1}. The strict comparison keeps the earliest window on a tie. - Return
answer.
The solution in Go
func maxSum(nums []int, k int) []int {
answer := []int{0, k - 1}
sum := 0
for i := 0; i < k; i++ {
sum += nums[i]
}
maxSum := sum
for i := 1; i <= len(nums)-k; i++ {
sum = sum - nums[i-1] + nums[i+k-1]
if sum > maxSum {
maxSum = sum
answer = []int{i, i + k - 1}
}
}
return answer
}
Go details to notice:
- A local variable can reuse the function's name. Inside
maxSum, the linemaxSum := sumdeclares a variable with the same name as the function. That is legal because the new name shadows the function within its scope. It works here since the function never calls itself, but a different name such asbestis safer. - Plain
=against:=.sum = sum - nums[i-1] + nums[i+k-1]updates the existing variable. Writing:=there would declare a newsuminside the loop and leave the outer one unchanged. - Index expressions are checked. If the slice is shorter than
k,nums[i]in the first loop panics with an index-out-of-range error. Go never reads past the end silently. len(nums)-kcan be negative, becauseintis signed. That is why the loop condition simply fails instead of wrapping around.
Tracing the example
With nums = [5, 6, 1, 2, 6, 6, 4, 3] and k = 3, the first window 5, 6, 1 has sum 12, so sum and maxSum start at 12 and answer is [0 2].
i = 1: subtract 5, add 2. The sum is 9, which is not better.i = 2: subtract 6, add 6. The sum is 9.i = 3: subtract 1, add 6. The sum is 14, which beats 12, soanswerbecomes[3 5].i = 4: subtract 2, add 4. The sum is 16, a new best, soanswerbecomes[4 6].i = 5: subtract 6, add 3. The sum is 13, which is not better.
The loop ends after i = 5 because len(nums)-k is 5, and the function returns [4 6]. Each step touched only two elements of the slice, instead of three, and the saving grows with k: for a window of 1,000 elements it is two operations instead of 1,000 per step.
Complexity
Time: O(n). The first loop does k additions and the second does at most n - k iterations of constant work, so the total is at most n steps.
Space: O(1). The function keeps a few integers and the two-element answer.
Edge cases and common mistakes
- The first window is the best. For
[9, 1, 1, 1]andk = 2the answer is[0 1]. This is whyanswerstarts as the first window. - All negative numbers. For
[-5, -2, -7]andk = 2the answer is[0 1]. BecausemaxSumstarts from a real window sum and not from 0, negative totals work. - Ties. For
[2, 2, 2]andk = 2, both windows sum to 4 and the answer is[0 1]. kequal to the length. There is one window, the loop body never runs, and the answer is[0, k - 1].- Wrong element leaving the window. The element to subtract is
nums[i-1], notnums[i]. The element to add isnums[i+k-1], the last element of the new window. klarger than the slice. With[1, 2]andk = 3the first loop panics, so check the length first if such input is possible.
Testing
[5, 6, 1, 2, 6, 6, 4, 3],k = 3gives[4 6].[-5, -2, -7],k = 2gives[0 1].[2, 2, 2],k = 2gives[0 1].[4, 1],k = 1gives[0 0].