2Brute2Best
🔥0

Maximum Sum Circular Subarray

Medium·LeetCode #918Basic Anchor
LeetCode
30-Second Mental ModelKadane twice (largest and smallest block) plus the total (Circular)
Complexity:O(N^2)→O(N)
Key Insight

A wrapping block is the whole circle minus one middle block, so its sum is total − (sum of the middle). To make the wrap as large as possible, make the middle block as small as possible. Run Kadane twice in one pass: once for the largest block and once for the smallest. The answer is the bigger of largest and total − smallest.

Core Validity Invariant

A wrapping block is total minus one non-empty middle block, so the best wrap is total minus the smallest middle block. The one exception is when every number is negative.

01

Problem

You are given an integer array nums that is circular: the element after the last one is the first one. A block of numbers can wrap around, going from the end of the array back to the start.

Return the largest sum of a non-empty block. A block may not use the same number twice.

Input

An integer array nums of length n, read as a circle.

Output

A single integer: the largest sum of any non-empty block on the circle.

Example 1
Input: nums = [1, -2, 3, -2]
Output: 3

The best block is [3] by itself. Wrapping does not help: [3, -2, 1] gives 2 and [1] gives 1.

Example 2
Input: nums = [5, -3, 5]
Output: 10

The block wraps around. The last 5 and the first 5 sit next to each other, so [5, 5] gives 10. Keeping the -3 in between would only give 7.

Example 3
Input: nums = [-3, -2, -3]
Output: -2

Every number is negative, so the best block is the least negative single number, -2.

Constraints
  • • n == nums.length
  • • 1 ≤ n ≤ 3 × 10^4
  • • −3 × 10^4 ≤ nums[i] ≤ 3 × 10^4
02

First, think yourself

Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.

  1. 1.

    For a normal array, Kadane finds the best block. What new kind of block appears when the array is a circle?

  2. 2.

    A block that wraps uses the end and the start of the array. Which part of the array does it leave out?

  3. 3.

    If a wrapping block skips a middle part, how is its sum related to the total sum of the array?

  4. 4.

    What happens to my answer if every single number is negative?

  5. 5.

    How many blocks can a circle of n numbers have, and can I check them all fast enough?

03

Brute force approach

04

Better approach

05

Optimized approach

06

Why does this algorithm work?

07

Dry run

08

All approaches compared

ApproachIdeaTimeSpace
Brute ForceWalk every block on the circle, using % n to wrap; keep the largest sumO(N^2)O(1)
BetterPrefix sums give any plain block; a wrap pairs the best prefix with the best suffixO(N)O(N)
OptimalRun Kadane for the largest and the smallest block sum; answer = max(largest, total − smallest)O(N)O(1)
09

Why does this belong to this pattern?

Clues in the problem statement
  • “circular array”The array is a circle, so a block can wrap from the end back to the start.
  • “non-empty block”The answer is a contiguous block on the circle. A wrapping block is the complement of one middle block.
  • “largest sum”Maximising the wrap means minimising the middle, so the same Kadane runs for the smallest sum too.
Circular contiguous block+wrap = total − middle block+answer = max(Kadane max, total − Kadane min), unless all are negative→Kadane twice (largest and smallest block) plus the total (Circular)

This is Kadane applied to the complement. A plain maximum-subarray question stops at the array's ends, but a circular block can wrap, and a wrapping block is the total minus one middle block. So the same Kadane that finds the largest sum also finds the smallest middle block, and the answer uses both. The all-negative guard is the one extra rule that only the circle needs.

10

Don't make this mistake

Pattern confusion: forgetting the all-negative case
✗ return max(maxK, total - minK);
✓ if (maxK < 0) return maxK; return max(maxK, total - minK);

On [-3, -2, -3] the smallest middle block is the whole array, which sums to -8. So total - minK = -8 - (-8) = 0. That is the empty block, and the code returns 0 instead of -2. Every number is negative, so the best answer is the least negative number, -2.

Subtracting the largest block instead of the smallest
✗ return max(maxK, total - maxK);
✓ return max(maxK, total - minK);

On the dry run [5, -4, 6, -3, -2, 5] the total is 7 and the largest plain block is 7. So total - maxK = 0, which is not a real block. The real wrap is 7 - (-5) = 12, which removes the smallest middle block [-3, -2].

Reading past the end in the brute force
✗ sum += nums[start + len - 1];
✓ sum += nums[(start + len - 1) % n];

The brute force must wrap. On [5, -4, 6, -3, -2, 5], start 4 with length 3 reads index 6, which does not exist. The modulo sends it back to index 0, the 5 at the front of the array.

11

Want to implement this?

Write it yourself on LeetCode, then come back and compare your code with the solutions above.

Open coding workspace
How did it go?
Beyond The LeetCode Problem

How this concept connects to System Design & C++ Systems

Bridge DSA with production engineering

Top engineering interviews test whether you understand how algorithms like DP — Kadane / Subarray translate into production architectures and low-level memory mechanics.