1013. 将数组分成和相等的三个部分
来源第 129 场周赛 Q1难度简单分数1378
题目描述
给你一个整数数组 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
提示:
3 <= arr.length <= 5 * 104-104 <= arr[i] <= 104
解法
方法一:遍历求和
思考
枚举两处切割点使三段和相等需要 \(O(n^2)\),数组长度通常达 \(10^4\) 量级,应当避免双重扫描。三段相等当且仅当总和能被 \(3\) 整除,且存在至少三段各自累加到 \(s=\textit{sum}/3\)。
从左到右累加,每达到一次 \(s\) 就重置并计数。多出来的段可以并入最后一部分,因此计数不少于 \(3\) 即可,而不必恰好切在两个固定下标。
先判断总和模 \(3\),再用一次遍历维护当前段和与段数。
我们先求出整个数组的和,然后判断和是否能被 3 整除,如果不能,直接返回 \(\textit{false}\)。
否则,我们记 \(\textit{s}\) 表示每部分的和,用一个变量 \(\textit{cnt}\) 记录当前已经找到的部分数,另一个变量 \(\textit{t}\) 记录当前部分的和。初始时 \(\textit{cnt} = 0\), \(t = 0\)。
然后我们遍历数组,对于每个元素 \(x\),我们将 \(t\) 加上 \(x\),如果 \(t\) 等于 \(s\),说明找到了一部分,将 \(\textit{cnt}\) 加一,然后将 \(t\) 置为 0。
最后判断 \(\textit{cnt}\) 是否大于等于 3 即可。
时间复杂度 \(O(n)\),其中 \(n\) 是数组 \(\textit{arr}\) 的长度。空间复杂度 \(O(1)\)。
1 2 3 4 5 6 7 8 9 10 11 12 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |