给你一个整数数组 A,只有可以将其划分为三个和相等的非空部分时才返回 true,否则返回 false。
形式上,如果可以找出索引 i+1 < j 且满足 (A[0] + A[1] + ... + A[i] == A[i+1] + A[i+2] + ... + A[j-1] == A[j] + A[j-1] + ... + A[A.length - 1]) 就可以将数组三等分。
示例 1:
输出:[0,2,1,-6,6,-7,9,1,2,0,1]
输出:true
解释:0 + 2 + 1 = -6 + 6 - 7 + 9 + 1 = 2 + 0 + 1
示例 2:输入:[0,2,1,-6,6,7,9,-1,2,0,1]
输出:false
示例 3:输入:[3,3,6,5,-2,2,5,1,-9,4]
输出:true
解释:3 + 3 = 6 = 5 - 2 + 2 + 5 + 1 - 9 + 4
解题思路:
方法一:寻找切分点
我们将数组 A 中的所有数的和记为 sum(A)。根据题目我们可以得知,每一个非空部分的和都应当是 sum(A) / 3。因此我们需要找到索引 i 和 j 使得:(1)A[0] + A[1] + ... + A[i] = sum(A) / 3;
(2)A[i + 1] + A[i + 2] + ... + A[j] = sum(A) / 3。
(1)+(2)这等价于 A[0] + A[1] + ... + A[j] = sum(A) / 3 * 2 且 j > i。
首先我们需要找出索引 i。具体地,我们从第一个元素开始遍历数组 A 并对数组中的数进行累加。当累加的和等于 sum(A) / 3 时,我们就将当前的位置置为索引 i。由于数组中的数有正有负,我们可能会得到若干个索引 i0, i1, i2, ...,从 A[0] 到这些索引的数之和均为 sum(A) / 3。那么我们应该选取那个索引呢?直觉告诉我们,应该贪心地选择最小的那个索引 i0,这也是可以证明的:假设最终的答案中我们选取了某个不为 i0 的索引 ik 以及另一个索引 j,那么根据上面的两条要求,有:
A[0] + A[1] + ... + A[ik] = sum(A) / 3;
A[0] + A[1] + ... + A[j] = sum(A) / 3 * 2 且 j > ik。
然而 i0 也是满足第一条要求的一个索引,因为 A[0] + A[1] + ... + A[i0] = sum(A) / 3 并且 j > ik > i0,我们可以将 ik 替换为 i0,因此选择最小的那个索引是合理的。
在选择了 i0 作为 i 之后,我们从 i0 + 1 开始继续遍历数组 A 并进行累加,当累加的和等于 sum(A) / 3 * 2 时,我们就得到了索引 j,可以返回 true 作为答案。如果我们无法找到索引 i 或索引 j,或者 sum(A) 本身无法被 3 整数,那么我们返回 false。
int a = [0,2,1,-6,6,-7,9,1,2,0,1];
class Solution {
public boolean canThreePartsEqualSum(int[] A) {
//数组内元素的总和
int arraySum = 0;
for(int a : A){
arraySum += a;
}
//如果数组的总和和3 取余 != 0 那么直接返回false
if(arraySum % 3 != 0){
return false;
}
//算出数组的总和除以3的平均数
int avgSum = arraySum/3;
//从数组的0下标开始遍历 算出a[0]+a[1]+...+a[i-1]之间 相邻元素相加之和=avgSum 即算出了第一段的结束坐标
int stepSum = 0;
//第一段数组的求和结束后 标记+1 第二段数组的求和结束后 标记+1 因为初始的时候 我们就已经对数组平分了3段处理,所以
//第3段 肯定符合 最终标记字段总数=2 即数组符合标准
int flgCount = 0;
for(int i =0;i<A.length;i++){
stepSum += A[i];
if(flgCount == 2){
return true;
}
if(stepSum == avgSum){
stepSum = 0;
flgCount ++;
}
}
//默认返回false
return false;
}
}