Kadane's Algorithm Maximum Subarray in DSA Go - Time & Space Complexity
We want to understand how the time needed to find the maximum sum of a continuous subarray changes as the input size grows.
How does the number of steps grow when the array gets bigger?
Analyze the time complexity of the following code snippet.
func maxSubArray(nums []int) int {
maxSoFar := nums[0]
maxEndingHere := nums[0]
for _, num := range nums[1:] {
maxEndingHere += num
if maxEndingHere < num {
maxEndingHere = num
}
if maxSoFar < maxEndingHere {
maxSoFar = maxEndingHere
}
}
return maxSoFar
}
This code finds the largest sum of any continuous subarray inside the given array.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Single loop through the array elements.
- How many times: Exactly once for each element in the array.
As the array size grows, the number of steps grows directly in proportion.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps |
| 100 | About 100 steps |
| 1000 | About 1000 steps |
Pattern observation: Doubling the input size roughly doubles the work done.
Time Complexity: O(n)
This means the time to find the maximum subarray sum grows linearly with the size of the input array.
[X] Wrong: "Since we check sums of subarrays, it must be O(n²) because of nested loops."
[OK] Correct: Kadane's algorithm cleverly keeps track of sums as it goes, avoiding repeated work and nested loops.
Understanding this linear-time solution shows you can find efficient answers to problems that seem complex at first, a key skill in interviews.
"What if we wanted to find the maximum subarray sum but also return the start and end indexes? How would the time complexity change?"
Practice
Solution
Step 1: Understand the problem Kadane's Algorithm solves
Kadane's Algorithm is designed to find the maximum sum of any contiguous subarray within a given array.Step 2: Compare with other options
Options B, C, and D describe different problems unrelated to Kadane's Algorithm.Final Answer:
The maximum sum of a contiguous subarray -> Option CQuick Check:
Maximum subarray sum = answer [OK]
- Confusing maximum subarray sum with total sum
- Thinking it finds minimum or longest subsequence
- Assuming it sorts the array
Solution
Step 1: Understand initialization in Kadane's Algorithm
We start with the first element as both maxSoFar and maxEndingHere to handle negative numbers correctly.Step 2: Analyze options
maxSoFar, maxEndingHere := nums[0], nums[0] initializes both variables with the first element, which is the correct approach. Other options either use zero or math.MinInt incorrectly.Final Answer:
maxSoFar, maxEndingHere := nums[0], nums[0] -> Option BQuick Check:
Initialize with first element to handle negatives [OK]
- Initializing maxSoFar to 0 causes errors with all negatives
- Using math.MinInt without importing math package
- Starting maxEndingHere at 0 instead of first element
func maxSubArray(nums []int) int {
maxSoFar, maxEndingHere := nums[0], nums[0]
for i := 1; i < len(nums); i++ {
if maxEndingHere < 0 {
maxEndingHere = nums[i]
} else {
maxEndingHere += nums[i]
}
if maxEndingHere > maxSoFar {
maxSoFar = maxEndingHere
}
}
return maxSoFar
}
fmt.Println(maxSubArray([]int{-2,1,-3,4,-1,2,1,-5,4}))Solution
Step 1: Trace the iteration and update maxEndingHere and maxSoFar
Start with maxSoFar = -2, maxEndingHere = -2.
i=1: maxEndingHere < 0, so maxEndingHere=1; maxSoFar=1
i=2: maxEndingHere=1+(-3)=-2; maxSoFar=1
i=3: maxEndingHere<0, maxEndingHere=4; maxSoFar=4
i=4: maxEndingHere=4+(-1)=3; maxSoFar=4
i=5: maxEndingHere=3+2=5; maxSoFar=5
i=6: maxEndingHere=5+1=6; maxSoFar=6
i=7: maxEndingHere=6+(-5)=1; maxSoFar=6
i=8: maxEndingHere=1+4=5; maxSoFar=6Step 2: Determine final maxSoFar
After loop, maxSoFar is 6, which is the maximum subarray sum.Final Answer:
6 -> Option DQuick Check:
Max subarray sum = 6 [OK]
- Adding negative numbers without reset
- Not updating maxSoFar correctly
- Starting loop from 0 instead of 1
func maxSubArray(nums []int) int {
maxSoFar, maxEndingHere := 0, 0
for _, num := range nums {
maxEndingHere = max(num, maxEndingHere + num)
maxSoFar = max(maxSoFar, maxEndingHere)
}
return maxSoFar
}
func max(a, b int) int {
if a > b {
return a
}
return b
}Solution
Step 1: Check initialization of maxSoFar and maxEndingHere
Initializing both to 0 causes wrong results if all numbers are negative because maxSoFar starts too low.Step 2: Correct initialization
They should be initialized to nums[0] to correctly handle negative values and start with the first element.Final Answer:
maxSoFar and maxEndingHere should start at nums[0], not 0 -> Option AQuick Check:
Initialize with first element to handle negatives [OK]
- Starting maxSoFar at 0 causes wrong max for negatives
- Confusing maxSoFar and maxEndingHere roles
- Returning wrong variable at end
Solution
Step 1: Understand how to track indices in Kadane's Algorithm
When maxEndingHere resets to current element, record that index as potential start. When maxSoFar updates, record current index as end.Step 2: Compare with other options
Store all subarrays and pick the max at the end and C are brute force and inefficient. Keep a count of positive numbers and return their indices is unrelated to max subarray indices.Final Answer:
Track start index when maxEndingHere resets; update end index when maxSoFar changes -> Option AQuick Check:
Track start on reset, update end on max update [OK]
- Not updating start index when resetting maxEndingHere
- Using nested loops instead of Kadane's approach
- Ignoring indices and returning only sum
Ready to prove it?
Pass the test and this pattern moves unknown
