给你一个整数数组 arr,只有可以将其划分为三个和相等的 非空 部分时才返回 true,否则返回 false。
形式上,如果可以找出索引 i + 1 < j 且满足 (arr[0] + arr[1] + ... + arr[i] == arr[i + 1]+ arr[i + 2] + ... + arr[j - 1] == arr[j] + arr[j + 1] + ... + arr[arr.length - 1])就可以将数组三等分。
示例 1:
输入: arr = [0,2,1,-6,6,-7,9,1,2,0,1]
输出: true
解释: 0 + 2 + 1 = -6 + 6 - 7 + 9 + 1 = 2 + 0 + 1
示例 2:
输入: arr = [0,2,1,-6,6,7,9,-1,2,0,1]
输出: false
示例 3:
输入:arr = [3,3,6,5,-2,2,5,1,-9,4]
输出:true
解释:3 + 3 = 6 = 5 - 2 + 2 + 5 + 1 - 9 + 4
题解:
/**
* @param {number[]} arr
* @return {boolean}
*/
// 方法一:遍历计数
var canThreePartsEqualSum = function (arr) {
// 求和
let sum = arr.reduce((pre, cur) => pre + cur)
// 如果余数不等于0,说明没法分成3等份
if (sum % 3 !== 0) {
return false;
}
let cnt = 0 // 计数
let tem = 0 // 累加
for (let i = 0; i < arr.length; i++) {
tem += arr[i]
if (tem == sum / 3) {
cnt++
tem = 0
}
}
// sum不为0且 cnt == 3 时 return true
// sum为0且 cnt > 3 时 return true(🌰[0, 0, 0, 0])
return cnt >= 3
};
// 方法二:贪心
var canThreePartsEqualSum = function (arr) {
// 计算出数组arr的和
const sumArr = arr.reduce((per, cur) => per + cur);
// 如果余数不等于0,说明没法分成3等份
if (sumArr % 3 !== 0) {
return false;
}
// 目标值,即每一等份需要凑成的值
const Target = sumArr / 3;
// 当前累加的和
let currentSum = 0;
// 第一个和为Target的数组的索引终止位置
let i = 0;
// 递归查找最小的终止索引i
while (i < arr.length) {
// 累计计算截至到当前索引i的数组和
currentSum += arr[i];
// 当当前数组和等于目标值时
if (currentSum === Target) {
// 退出循环
break;
}
// 否则则继续进行累加
i++;
}
/*
关键点1
这一步的判断,其实本质上是比较 数组arr的和 与 其值的三分之一
因为在关键点1中,
如果是通过break语句退出循环的,则二者必然相等,不可能执行本处if代码块里的内容。
反之,如果不是通过break语句退出的,
则意味着整个数组arr的项值都被累加进入变量currentSum中
*/
if (currentSum !== Target) {
/*
返回false的涵义:
请牢记,currentSum是数组arr的总和(在if代码块内时),
Target是数组A总和的三分之一
举例:
数组arr的和为9,9可以被分成三等份,但是不意味着,数组arr就可以被等分成3个值为3的子数组,
例如: 当数组A为[1,4,4]时,总和为9,能被3整除,可分成3份后每份值都不等([1], [4], [4])
*/
return false;
}
/*
第二个数值的终止索引,
由于从索引0到索引i的值以满足Target,
则第二个数组的起始值该为i+1
*/
let j = i + 1;
/*
关键点2
while循环最多只到j + 1 < arr.length为止
因为至少需要留一个项数为1的数组来满足等份三份的需求
*/
while (j + 1 < arr.length) {
currentSum += arr[j];
if (currentSum === Target * 2) {
/*
关键点3
如果进入了这个if代码块内,
则证明已经有2个数组的和等同于Target了
又因为预先保证了至少预留一位的数组(while( j + 1 < arr.length))
所以一共有3个数组的满足了Target了,
所以可以直接返回true
*/
return true;
}
j++;
}
/*
这里的返回false是因为满足了第一个while循环,没有满足第二个while循环
即只有一个数组的和等于Target
*/
return false;
};
来源:力扣(LeetCode)
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。