Problem Overview
LeetCode 724 — Find Pivot Index asks you to return the leftmost index in the array where the sum of all numbers strictly to the left equals the sum of all numbers strictly to the right. The element at the pivot index itself is not included in either sum. If no such index exists, return -1.
This problem is a classic application of the prefix sum pattern. The naive approach checks every index by computing left and right sums independently for each candidate, resulting in O(n²) time. The efficient approach precomputes the total sum and maintains a running left sum, reducing the problem to a single O(n) scan with O(1) extra space.
Edge cases matter here: an index of 0 is a valid pivot if the total sum of elements from index 1 onward equals 0, because the left side is empty (sum = 0). Similarly, the last index is a valid pivot if all preceding elements sum to 0. Always handle these boundary cases with the same formula — no special-casing needed.
- Return the leftmost index where sum(nums[0..i-1]) == sum(nums[i+1..n-1])
- The element at the pivot index is NOT counted in either left or right sum
- If no pivot exists, return -1
- If multiple pivot indices exist, return the leftmost one
- Index 0 is a valid pivot if sum(nums[1..n-1]) == 0; last index is valid if sum(nums[0..n-2]) == 0
Prefix Sum Approach
The key insight is that you do not need to recompute the left and right sums from scratch at every index. Instead, compute the totalSum of the entire array once in O(n). Then maintain a running leftSum initialized to 0. At each index i, the rightSum is totalSum minus leftSum minus nums[i] — computed in O(1).
After checking whether leftSum equals rightSum at index i, update leftSum by adding nums[i] before moving to index i+1. This way leftSum always represents the sum of all elements strictly to the left of the current index, and rightSum is derived from it in constant time using the total sum.
The algorithm terminates as soon as the first pivot is found, returning that index immediately. If the full array is traversed without finding a pivot, return -1. Both the time complexity and space complexity are optimal: O(n) time for the initial sum and single scan, O(1) extra space since only totalSum and leftSum are stored.
Derive rightSum in O(1) — No Second Array Needed
You do not need two separate prefix arrays for left and right sums. Once you know totalSum and leftSum, rightSum is simply totalSum minus leftSum minus nums[i]. This O(1) derivation is what makes the single-pass approach work. Allocating a right-sum array would still be O(n) time but uses O(n) space unnecessarily — the running-leftSum trick avoids it entirely.
Algorithm Steps
The algorithm is concise: one pass to compute totalSum, one pass to find the pivot. Both passes are O(n), making the overall complexity O(n). The pivot check and leftSum update inside the loop are O(1) each, so no nested loops are needed.
It is critical that leftSum is updated AFTER the pivot check at each index. Before the check, leftSum must represent the sum of elements strictly to the LEFT of index i, which excludes nums[i]. After a failed check, add nums[i] to leftSum before advancing to the next index.
This approach is also naturally correct for the leftmost pivot requirement: the loop iterates left to right and returns at the first match, so the result is always the smallest valid index without any additional tracking.
- 1Compute totalSum = sum(nums) — O(n)
- 2Initialize leftSum = 0
- 3For i in range(len(nums)):
- 4 Compute rightSum = totalSum - leftSum - nums[i]
- 5 If leftSum == rightSum: return i (pivot found)
- 6 Update leftSum += nums[i]
- 7After loop completes: return -1 (no pivot)
Why This Is Prefix Sum
Formally, leftSum at index i equals prefix[i], where prefix[i] is the sum of nums[0..i-1]. The rightSum equals totalSum minus prefix[i] minus nums[i], which equals totalSum minus prefix[i+1]. The pivot condition leftSum == rightSum becomes prefix[i] == totalSum - prefix[i+1], or equivalently 2*prefix[i] + nums[i] == totalSum.
This alternate formulation — 2*leftSum + nums[i] == totalSum — avoids computing rightSum as a separate variable. It checks balance using only leftSum, nums[i], and totalSum. Both formulations are mathematically equivalent; choose whichever feels more readable in your implementation.
Understanding the prefix-sum foundation makes it easier to generalize: any problem asking for a balance point, equilibrium index, or split condition where left equals right can often be solved with this pattern. The same idea appears in problems like find the winner of an array game, minimum operations to equalize array halves, and more.
Alternate: 2*leftSum + nums[i] == totalSum
The condition 2*leftSum + nums[i] == totalSum is algebraically equivalent to leftSum == rightSum. Deriving it: leftSum == totalSum - leftSum - nums[i] → 2*leftSum == totalSum - nums[i] → 2*leftSum + nums[i] == totalSum. Some find this form cleaner because it avoids a separate rightSum variable and makes the single-equation pivot check more explicit.
Walk-Through Example
Consider nums = [1, 7, 3, 6, 5, 6]. The total sum is 1+7+3+6+5+6 = 28. Now scan left to right, maintaining leftSum = 0 initially and computing rightSum at each step.
At i=0: rightSum = 28 - 0 - 1 = 27. leftSum (0) != rightSum (27), so update leftSum to 0+1=1. At i=1: rightSum = 28 - 1 - 7 = 20. leftSum (1) != rightSum (20), update leftSum to 1+7=8. At i=2: rightSum = 28 - 8 - 3 = 17. leftSum (8) != rightSum (17), update leftSum to 8+3=11.
At i=3: rightSum = 28 - 11 - 6 = 11. leftSum (11) == rightSum (11) — pivot found! Return 3. Verify manually: left of index 3 = 1+7+3 = 11; right of index 3 = 5+6 = 11. Correct.
- 1nums = [1, 7, 3, 6, 5, 6] → totalSum = 28
- 2i=0: leftSum=0, rightSum=28-0-1=27 → 0 != 27 → leftSum=1
- 3i=1: leftSum=1, rightSum=28-1-7=20 → 1 != 20 → leftSum=8
- 4i=2: leftSum=8, rightSum=28-8-3=17 → 8 != 17 → leftSum=11
- 5i=3: leftSum=11, rightSum=28-11-6=11 → 11 == 11 → return 3
- 6Verify: sum([1,7,3])=11, sum([5,6])=11 ✓
Code Walkthrough — Python and Java
Python: def pivotIndex(nums): total=sum(nums); left=0; for i,n in enumerate(nums): if left==total-left-n: return i; left+=n; return -1. The built-in sum() computes totalSum in O(n), then the for loop runs one more O(n) pass. Total: O(n) time, O(1) space. Clean and concise — five lines of logic.
Java: public int pivotIndex(int[] nums) { int total=0; for(int n:nums) total+=n; int left=0; for(int i=0;i<nums.length;i++) { if(left==total-left-nums[i]) return i; left+=nums[i]; } return -1; }. Same structure: first loop accumulates total, second loop checks pivot. Both loops are O(n); space is O(1).
Both solutions handle all edge cases naturally: empty-left pivot (index 0) works because left=0 and right=total-0-nums[0]=total-nums[0]; empty-right pivot (last index) works because after all additions left equals total-nums[last]. No special-casing needed for any boundary.
Update leftSum AFTER the Comparison — Not Before
Always update leftSum += nums[i] AFTER the pivot check at index i, not before. The leftSum at the moment of comparison must represent the sum of elements strictly to the LEFT of index i, which means nums[i] itself must not yet be included. Updating leftSum before the check would include nums[i] in the left sum, making it represent prefix[i+1] instead of prefix[i], and the comparison would be wrong.