Problem overview
The function maxSum receives an IntArray called nums and a positive integer k. Among all contiguous subarrays of length exactly k, it must find the one with the largest sum, and return its first and last index as a two-element IntArray.
In the example, nums = [5, 6, 1, 2, 6, 6, 4, 3] and k = 3. The window [6, 6, 4], at indices 4 to 6, sums to 16, more than any other window of three. The function returns [4, 6].
Approach: slide the window instead of re-adding it
The straightforward solution sums every window from scratch: k additions for each of the n - k + 1 windows, which is O(n * k). But two neighbouring windows differ by only two elements. When the window moves one step right, the element at its left edge leaves and a new element enters at its right edge. The new sum is
new sum = old sum - (element that left) + (element that entered)
That costs two operations no matter how large k is. The only full sum is the one for the very first window, so the total work is about k + (n - k) steps, which is O(n).
Take the example. The first window [5, 6, 1] sums to 12. Sliding to start 1, the 5 leaves and the 2 enters: 12 - 5 + 2 = 9, which matches 6 + 1 + 2. Sliding to start 2, the 6 leaves and the 6 enters: 9 - 6 + 6 = 9. Next, 9 - 1 + 6 = 14, then 14 - 2 + 4 = 16, and finally 16 - 6 + 3 = 13. The best sum, 16, belongs to the window that started at index 4.
Step by step
- Start
answeras the first window. Declare it withvarand give it the bounds0andk - 1. If no later window is better, the first one is the result, so an empty starting answer would return nothing in that case. - Declare
sumwithvar, starting at 0. It will always hold the sum of the current window. - Add up the first window. Loop
ifrom 0 tok - 1and addnums[i]tosum. Usinguntil kstops the loop at indexk - 1. - Declare
maxSumwithvar, initialized withsum. The first window is the best seen so far. - Set up a
whileloop over the remaining starts. Declarevar i = 1and loop whilei <= nums.size - k, withi++as the last line of the body. Window starts 1 tonums.size - kremain. - Slide the window. At the top of the body, subtract
nums[i - 1], the element that just left, and addnums[i + k - 1], the element that just entered. The window starting aticoversitoi + k - 1, and the previous one started ati - 1. - Compare. If
sumis greater thanmaxSum, save it and setanswertointArrayOf(i, i + k - 1). The strict>keeps the earliest window on ties. - Return
answerafter the loop. The incrementi++sits at the bottom of the body, below the comparison, so the steps above run beforeiadvances.
The solution in Kotlin
class Solution {
fun maxSum(nums: IntArray, k: Int): IntArray {
var answer = intArrayOf(0, k - 1)
var sum = 0
for (i in 0 until k) {
sum += nums[i]
}
var maxSum = sum
var i = 1
while (i <= nums.size - k) {
sum = sum - nums[i - 1] + nums[i + k - 1]
if (sum > maxSum) {
maxSum = sum
answer = intArrayOf(i, i + k - 1)
}
i++
}
return answer
}
}
The Kotlin details worth a closer look:
- Two different
is. The loop variable offor (i in 0 until k)exists only inside that loop. After the loop ends,var i = 1declares a new variable with the same name, which is legal because the first one is out of scope. - A
whileloop for a manual counter. Theforloop would also work here, for examplefor (i in 1..nums.size - k). The lesson useswhileso that the start index and the increment are visible. Forgettingi++would make the loop run forever. - Precedence. In
nums.size - k, the subtraction happens before the comparison withi, so no parentheses are needed. IntArraycreation.intArrayOf(0, k - 1)builds a new two-element array. Each improvement allocates another small array, but only when a better window is found.Intoverflow. The running sum is anInt, so totals beyond about 2.1 billion wrap around silently. ALongwould avoid that.
Complexity
Time: O(n). The first loop runs k times and the while loop runs n - k times. Each pass of the while loop does a constant amount of work. Every element enters the window once and leaves it at most once.
Space: O(1). Apart from the two-element answer, only a few integers are stored. Compared with the brute force, the time drops from O(n * k) to O(n) at no cost in memory.
Edge cases and common mistakes
kequals the array length. The condition1 <= nums.size - kis false at once, so the loop doesn't run and the first window[0, k - 1]is returned.- Ties. For
[2, 2, 2, 2]withk = 2every window sums to 4. The strict>keeps the earliest, so the function returns[0, 1]. - All negative numbers.
[-5, -1, -9]withk = 1returns[1, 1]. BecausemaxSumstarts as the first window's sum, rather than 0, a negative sum can still win. - Wrong indices when sliding. The element that leaves is
nums[i - 1], and the one that enters isnums[i + k - 1]. Usingnums[i + k]for the new element reads one position too far, and at the last window it goes past the end of the array. - Resetting the sum. Setting
sumback to 0 inside the loop would defeat the purpose and lose the previous window's total. klarger than the array. The first loop readsnums[i]beyond the last index and throws anArrayIndexOutOfBoundsException. The lesson's inputs keepkwithin the array.
Testing
nums = [5, 6, 1, 2, 6, 6, 4, 3],k = 3gives[4, 6].nums = [2, 2, 2, 2],k = 2gives[0, 1].nums = [-5, -1, -9],k = 1gives[1, 1].