LeetCode 1013: Partition Array Into Three Parts With Equal Sum (Prefix Sum Cut Points)
LeetCode 1013ArrayPrefix SumToday we solve LeetCode 1013 - Partition Array Into Three Parts With Equal Sum.
Source: https://leetcode.com/problems/partition-array-into-three-parts-with-equal-sum/
English
Problem Summary
Given an integer array arr, determine whether it can be split into three non-empty contiguous parts whose sums are equal.
Key Insight
If the total sum is S, each part must sum to target = S / 3. So S must be divisible by 3 first. Then scan prefix sums and find:
- first cut where prefix sum equals target, and
- second cut where prefix sum equals 2 * target.
As long as the second cut is before the last element, the remaining suffix is the third non-empty part.
Algorithm
- Compute total sum S; if S % 3 != 0, return false.
- Set target = S / 3, and keep running prefix sum.
- Scan to n - 2 (leave at least one element for part 3).
- Record when prefix hits target; then look for prefix 2 * target.
- If found in order, return true; otherwise false.
Complexity Analysis
Time: O(n).
Space: O(1).
Common Pitfalls
- Forgetting parts must be non-empty.
- Scanning all the way to the last index (which can make the third part empty).
- Not handling negative numbers (the prefix method still works with negatives).
Reference Implementations (Java / Go / C++ / Python / JavaScript)
class Solution {
public boolean canThreePartsEqualSum(int[] arr) {
int total = 0;
for (int v : arr) total += v;
if (total % 3 != 0) return false;
int target = total / 3;
int prefix = 0;
boolean firstFound = false;
for (int i = 0; i < arr.length - 1; i++) {
prefix += arr[i];
if (!firstFound) {
if (prefix == target) firstFound = true;
} else {
if (prefix == 2 * target) return true;
}
}
return false;
}
}func canThreePartsEqualSum(arr []int) bool {
total := 0
for _, v := range arr {
total += v
}
if total%3 != 0 {
return false
}
target := total / 3
prefix := 0
firstFound := false
for i := 0; i < len(arr)-1; i++ {
prefix += arr[i]
if !firstFound {
if prefix == target {
firstFound = true
}
} else {
if prefix == 2*target {
return true
}
}
}
return false
}class Solution {
public:
bool canThreePartsEqualSum(vector<int>& arr) {
int total = 0;
for (int v : arr) total += v;
if (total % 3 != 0) return false;
int target = total / 3;
int prefix = 0;
bool firstFound = false;
for (int i = 0; i < (int)arr.size() - 1; ++i) {
prefix += arr[i];
if (!firstFound) {
if (prefix == target) firstFound = true;
} else {
if (prefix == 2 * target) return true;
}
}
return false;
}
};class Solution:
def canThreePartsEqualSum(self, arr: List[int]) -> bool:
total = sum(arr)
if total % 3 != 0:
return False
target = total // 3
prefix = 0
first_found = False
for i in range(len(arr) - 1):
prefix += arr[i]
if not first_found:
if prefix == target:
first_found = True
else:
if prefix == 2 * target:
return True
return Falsevar canThreePartsEqualSum = function(arr) {
let total = 0;
for (const v of arr) total += v;
if (total % 3 !== 0) return false;
const target = total / 3;
let prefix = 0;
let firstFound = false;
for (let i = 0; i < arr.length - 1; i++) {
prefix += arr[i];
if (!firstFound) {
if (prefix === target) firstFound = true;
} else {
if (prefix === 2 * target) return true;
}
}
return false;
};中文
题目概述
给定整数数组 arr,判断是否可以把它分成三个非空且连续的部分,并且三部分的元素和相等。
核心思路
设总和为 S,若能三等分则每段和必须是 target = S / 3,因此第一步是检查 S 能否被 3 整除。
随后做前缀和扫描,按顺序寻找两个切分点:
- 第一个切分点:前缀和第一次等于 target;
- 第二个切分点:前缀和等于 2 * target。
只要第二个切分点在最后一个元素之前,就能保证第三段非空,且三段和相等。
算法步骤
- 计算总和 S,若 S % 3 != 0 直接返回 false。
- 令 target = S / 3,维护前缀和 prefix。
- 只遍历到 n - 2,给第三段至少留一个元素。
- 先找到 prefix == target,再找 prefix == 2 * target。
- 若按顺序找到,返回 true;否则返回 false。
复杂度分析
时间复杂度:O(n)。
空间复杂度:O(1)。
常见陷阱
- 忘记“三段都必须非空”。
- 扫描到最后一个元素,导致第三段可能为空。
- 误以为有负数时不能用前缀和(其实完全可以)。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
class Solution {
public boolean canThreePartsEqualSum(int[] arr) {
int total = 0;
for (int v : arr) total += v;
if (total % 3 != 0) return false;
int target = total / 3;
int prefix = 0;
boolean firstFound = false;
for (int i = 0; i < arr.length - 1; i++) {
prefix += arr[i];
if (!firstFound) {
if (prefix == target) firstFound = true;
} else {
if (prefix == 2 * target) return true;
}
}
return false;
}
}func canThreePartsEqualSum(arr []int) bool {
total := 0
for _, v := range arr {
total += v
}
if total%3 != 0 {
return false
}
target := total / 3
prefix := 0
firstFound := false
for i := 0; i < len(arr)-1; i++ {
prefix += arr[i]
if !firstFound {
if prefix == target {
firstFound = true
}
} else {
if prefix == 2*target {
return true
}
}
}
return false
}class Solution {
public:
bool canThreePartsEqualSum(vector<int>& arr) {
int total = 0;
for (int v : arr) total += v;
if (total % 3 != 0) return false;
int target = total / 3;
int prefix = 0;
bool firstFound = false;
for (int i = 0; i < (int)arr.size() - 1; ++i) {
prefix += arr[i];
if (!firstFound) {
if (prefix == target) firstFound = true;
} else {
if (prefix == 2 * target) return true;
}
}
return false;
}
};class Solution:
def canThreePartsEqualSum(self, arr: List[int]) -> bool:
total = sum(arr)
if total % 3 != 0:
return False
target = total // 3
prefix = 0
first_found = False
for i in range(len(arr) - 1):
prefix += arr[i]
if not first_found:
if prefix == target:
first_found = True
else:
if prefix == 2 * target:
return True
return Falsevar canThreePartsEqualSum = function(arr) {
let total = 0;
for (const v of arr) total += v;
if (total % 3 !== 0) return false;
const target = total / 3;
let prefix = 0;
let firstFound = false;
for (let i = 0; i < arr.length - 1; i++) {
prefix += arr[i];
if (!firstFound) {
if (prefix === target) firstFound = true;
} else {
if (prefix === 2 * target) return true;
}
}
return false;
};
Comments