Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 9

Kadane's Algorithm: Maximum Subarray Sum

Recommended resources

Welcome back! In our last lesson, we explored the two-pointer technique, a powerful pattern for optimizing array problems, often reducing complexity from a quadratic O(n²) to a linear O(n). We saw this in action with problems like "Two Sum" and "Move Zeros."

Today, we continue our journey through essential array algorithms by tackling another classic interview problem: finding the maximum sum of a contiguous subarray. You'll learn how to progress from a naive, brute-force solution to a beautifully efficient, linear-time algorithm. The goal of this lesson is to implement Kadane's algorithm, a famous and elegant technique that solves this problem in a single pass. Mastering this algorithm is a key step in building your problem-solving arsenal for technical interviews.

The Maximum Subarray Sum Problem

First, let's clearly define the problem. Given an array of integers, which can include both positive and negative numbers, we need to find the contiguous subarray (a sequence of adjacent elements) that has the largest possible sum. We then return that sum.

For example, given the array [-2, 1, -3, 4, -1, 2, 1, -5, 4], the subarray [4, -1, 2, 1] has the sum 6, which is the largest sum you can get from any contiguous subarray in this array.

Following your preferred learning style, let's start with the most straightforward approach and refine it until we arrive at the optimal solution.


Approach 1: The Brute-Force Solution O(n³)

The most direct way to solve this is to consider every single possible contiguous subarray, calculate the sum of each one, and keep track of the maximum sum we've seen.

How do we generate every subarray? We can use two nested loops to define the start and end points of the subarray.

  1. An outer loop (i) selects the starting index of the subarray.
  2. An inner loop (j) selects the ending index of the subarray.

Once we have a subarray defined by i and j, we need a third loop (k) to iterate from i to j and calculate its sum. This three-loop structure immediately points to a cubic time complexity, O(n³).

Let's use the tutorial from "takeUforward" as our guide through this process.

Kadane's Algorithm : Maximum Subarray Sum in an Array

This article from Striver's 'takeUforward' site follows our preferred structure of exploring brute-force, better, and optimal solutions. It will be our main reference for this lesson.

Begin by reading the problem description to solidify your understanding. Next, read the Brute Force section, focusing on the algorithm description. This explains the O(n³) three-loop logic. You can also glance at the Java code to see how it's implemented.

While this approach works, an O(n³) solution is highly inefficient and would be too slow for typical constraints in an interview or on a competitive programming platform.


Approach 2: A Better Solution O(n²)

We can make a simple but significant optimization. In the O(n³) approach, we repeatedly recalculated the sum of subarrays. Notice that when we extend a subarray [i...j] to [i...j+1], the new sum is just the old sum plus the new element array[j+1].

This insight allows us to eliminate the third loop. We can use just two loops:

  1. The outer loop (i) still selects the starting index.
  2. The inner loop (j) iterates from i to the end of the array. Inside this loop, we maintain a current_sum for the subarray [i...j], updating it by adding the element at j in each step.

This reduces the time complexity to O(n²). This is an improvement, but for large arrays (e.g., n = 10^5), n² is still too slow and would likely result in a "Time Limit Exceeded" error.

The Codecademy article provides a clear explanation of this optimization step.

Kadane's Algorithm: Find Maximum Subarray Sum in an ...

This article explains the transition from O(n³) to O(n²).

Read the section titled this section. It clearly explains the logic of removing the innermost loop by incrementally calculating the sum.

Now, let's make the leap to the optimal solution.


Approach 3: Optimal Solution - Kadane's Algorithm O(n)

Kadane's algorithm is a brilliant and intuitive dynamic programming approach that solves this problem in a single pass (O(n) time) and with constant extra space (O(1)).

The core idea is to iterate through the array while keeping track of two values:

  1. current_sum: The maximum sum of a subarray ending at the current position.
  2. max_so_far: The overall maximum sum found anywhere in the array so far.

Here's the logic:
For each element in the array, we add it to current_sum. Then, we update max_so_far if current_sum is greater.

The crucial step, and the main insight of the algorithm, is this: If current_sum ever becomes negative, we reset it to 0.

Why? A negative current_sum means the subarray ending at this point has a negative total. If we were to carry this negative sum forward, it would only decrease the sum of any future subarray. It's always better to abandon the negative-sum subarray and start a new one from the next element. Starting a new subarray is equivalent to resetting current_sum to 0 and then adding the next element.

Let's watch Striver's explanation of this intuition.

Kadane's Algorithm | Maximum Subarray Sum | Finding and Printing

This video provides a fantastic walkthrough of the intuition behind Kadane's algorithm.

Focus on the explanation of the optimal solution. Pay close attention to the logic of why we carry a positive sum forward but reset a negative sum to zero.

The following image provides a step-by-step visualization of the algorithm in action.

This image demonstrates Kadane's Algorithm on the array `[-2, 1, -3, 4, -1, 2, 1, -5, 4]`. It tracks the `Cur Sum` (current_sum) and `Max. Sum` (max_so_far) at each step. Notice how `Cur Sum` is reset to 0 (implicitly before adding the next element) after it becomes negative (e.g., at Step 3, `Cur Sum` is -2, so the next subarray starting at index 3 effectively starts from 0). The final `Max. Sum` is 6.

Now, let's solidify this with the formal algorithm description and Java code from our main resource.

Kadane's Algorithm : Maximum Subarray Sum in an Array

This section details the optimal algorithm and provides the Java implementation.

Read the Optimal Approach section. Study the algorithm steps and then examine the accompanying Java code. Note the simple loop structure and the if (sum < 0) condition, which is the heart of the algorithm.

Here is a clean Java implementation of Kadane's algorithm:

public class KadaneAlgorithm {
    public int maxSubArray(int[] nums) {
        long max_so_far = Long.MIN_VALUE; // Use long to avoid overflow, though problem constraints might not need it.
        long current_sum = 0;

        for (int i = 0; i < nums.length; i++) {
            current_sum = current_sum + nums[i];

            if (current_sum > max_so_far) {
                max_so_far = current_sum;
            }

            if (current_sum < 0) {
                current_sum = 0;
            }
        }
        
        // A special case: if all numbers are negative, max_so_far will be the largest (least negative) of them.
        // If the problem allowed an empty subarray (sum 0), you might need an extra check here.
        // For this standard version, this is sufficient.
        return (int) max_so_far;
    }
}

A quick note on an edge case: What if all the numbers in the array are negative, like [-5, -1, -3]? In this case, current_sum will be reset to 0 frequently, but max_so_far will correctly capture the largest (i.e., least negative) single element, which is -1. The implementation shown handles this correctly.


Follow-up: Printing the Subarray

A common follow-up question in interviews is to not only return the maximum sum but also print the actual subarray that produces it.

To do this, we can augment Kadane's algorithm:

  • We need variables ansStart and ansEnd to store the start and end indices of the best subarray found so far.
  • We also need a start variable to mark the potential beginning of a new subarray.
  • When does a new potential subarray start? Right after current_sum was reset to 0. So, when current_sum is 0, we can set start = i.
  • Whenever we update max_so_far, we also update ansStart = start and ansEnd = i.

The "takeUforward" resources cover this modification perfectly.

Kadane's Algorithm : Maximum Subarray Sum in an Array

This section explains how to modify the algorithm to find the indices.

Read the Follow Up section and study its approach description and the corresponding Java code. This is a very practical extension to know.


Conclusion

Today we've dissected the Maximum Subarray Sum problem, following our structured approach from a naive O(n³) solution to the beautifully simple and efficient O(n) Kadane's algorithm. This algorithm is a testament to how a clever insight can lead to a massive performance improvement.

Key Takeaways:

  • Problem Progression: We saw how to refine a brute-force O(n³) solution to a better O(n²) one, and finally to the optimal O(n) solution. This thought process is exactly what interviewers look for.
  • Kadane's Algorithm: A single-pass algorithm that efficiently finds the maximum subarray sum.
  • The Core Insight: The key is to discard any subarray prefix that has a negative sum, as it can't contribute positively to any larger subarray. This is achieved by resetting the current_sum to 0 whenever it becomes negative.
  • Interview Follow-up: You learned how to extend the basic algorithm to also return the start and end indices of the maximum sum subarray.

In our next lesson, we will dive into prefix sums. This technique allows you to answer range-sum queries (i.e., finding the sum of elements between any two indices) very efficiently, providing a different but equally powerful tool for solving array-based problems.