A clear explanation of checking if an array can be split into three contiguous parts with equal sum using a greedy two-pass approach.
Problem Restatement
We are given an integer array arr.
We need to return true if we can partition the array into three non-empty contiguous parts that each have the same sum.
Formally, find indices i and j such that:
0 < i < j < len(arr)
sum(arr[:i]) == sum(arr[i:j]) == sum(arr[j:])If such indices exist, return true. Otherwise return false.
The official constraints state that 3 <= arr.length <= 5 * 10^4 and -10^4 <= arr[i] <= 10^4.
Input and Output
| Item | Meaning |
|---|---|
| Input | Array arr |
| Output | true if a valid three-way partition exists |
| Partition | Three non-empty contiguous subarrays with equal sums |
Function shape:
def canThreePartsEqualSum(arr: list[int]) -> bool:
...Examples
Example 1:
arr = [0, 2, 1, -6, 6, -7, 9, 1, 2, 0, 1]Total sum is 9. Each part should sum to 3.
Partition: [0,2,1], [-6,6,-7,9,1], [2,0,1] → sums 3, 3, 3. ✓
Answer:
TrueExample 2:
arr = [0, 2, 1, -6, 6, 7, 9, -1, 2, 0, 1]Total sum is 21. Each part should sum to 7.
But no such partition exists.
Answer:
FalseKey Insight
The total sum must be divisible by 3. Each part must equal total / 3.
Scan the array while accumulating a running sum. Each time the running sum hits target, we have found one part boundary. After finding two boundaries, check if a third non-empty part remains.
Algorithm
- Compute
total = sum(arr). Iftotal % 3 != 0, returnFalse. - Set
target = total // 3. - Scan the array, tracking the running sum and the count of parts found.
- When the running sum equals
target * parts_found, increment the parts count. - If we found 3 parts and there are elements remaining, return
True(but ensure the third part is non-empty by requiring the boundary to be before the last element).
Simpler: scan for the first boundary, then the second boundary, then check elements remain.
Correctness
If total is not divisible by 3, no equal-sum partition exists.
If it is, we greedily find the earliest position where the prefix sum equals target. Then from there, find the next position where the cumulative sum equals 2 * target. If this second boundary is before the last element, the third part exists and is non-empty.
Edge Cases
- Check the minimum input size allowed by the constraints.
- Verify duplicate values or tie cases if the input can contain them.
- Keep the return value aligned with the exact failure case in the statement.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(n) | Single pass |
| Space | O(1) | Constant extra space |
Common Pitfalls
- Do not optimize away the invariant; the code should still make it clear what condition is being maintained.
- Prefer problem-specific names over one-letter variables once the logic becomes stateful.
Implementation
class Solution:
def canThreePartsEqualSum(self, arr: list[int]) -> bool:
total = sum(arr)
if total % 3 != 0:
return False
target = total // 3
parts = 0
running = 0
for i in range(len(arr)):
running += arr[i]
if running == target * (parts + 1):
parts += 1
if parts == 2 and i < len(arr) - 1:
return True
return FalseCode Explanation
Check divisibility:
if total % 3 != 0:
return FalseScan while counting part boundaries:
running += arr[i]
if running == target * (parts + 1):
parts += 1After finding the second boundary, check that we are not at the last element (ensuring the third part is non-empty):
if parts == 2 and i < len(arr) - 1:
return TrueTesting
def run_tests():
s = Solution()
assert s.canThreePartsEqualSum([0, 2, 1, -6, 6, -7, 9, 1, 2, 0, 1]) == True
assert s.canThreePartsEqualSum([0, 2, 1, -6, 6, 7, 9, -1, 2, 0, 1]) == False
assert s.canThreePartsEqualSum([3, 3, 6, 5, -2, 2, 5, 1, -9, 4]) == True
assert s.canThreePartsEqualSum([1, 1, 1]) == True
assert s.canThreePartsEqualSum([0, 0, 0, 0]) == True
print("all tests passed")
run_tests()| Test | Expected | Why |
|---|---|---|
[0,2,1,-6,6,-7,9,1,2,0,1] | True | Valid three-way partition |
[0,2,1,-6,6,7,9,-1,2,0,1] | False | No valid partition |
[3,3,6,5,-2,2,5,1,-9,4] | True | Another valid partition |
[1,1,1] | True | Each part is one element |
[0,0,0,0] | True | Multiple zero partitions |