Leetcode 927 -- 思维
题目描述
思路
题目要求我们将源数组划分为三个连续的序列,即 \([0,i],[i+1,j-1],[j,n-1]\) ,使得这三个序列的二进制所表示的数相等。
首先,我们需要挖掘出一个性质:存在这样三个序列的必要条件是 \(1\) 的个数必须为 \(3\) 的整数倍。
很显然如果不能满足这个条件,是没有办法将划分出满足条件的三个序列的。那么现在思路就清晰多了。
我们可以通过判断 \(1\) 的个数,找出每个序列的起点。注意,由于前导 \(0\) 的存在,我们要保证每个序列都从最高位的 \(1\) 开始,这样可以方便我们判断序列是否相同。
序列的长度就是最后一个序列的长度,因为最后一个序列从它的最高位到数组的最后一个数都是必须要选的。
题目要求我们返回第一个序列的结尾和第三个序列的开头。注意!由于我们忽略的前导 \(0\),所以这样我们不能直接返回我们前面求得的第三个序列的开头。不过,我们可以返回第二个序列的结尾的下一个元素,这个元素正是第三个序列的开头。
代码
class Solution {
public:
vector<int> threeEqualParts(vector<int>& arr) {
int cnt = 0, n = arr.size();
for(int i = 0; i < n; i ++ )
if(arr[i]) cnt ++ ;
if(cnt == 0) return {0, 2};
if(cnt % 3) return {-1, -1};
int part = cnt / 3;
// [0,i], [i+1,j-1], [j,n-1]
// 求出每个序列的忽略前导0的第一个元素(必然是1),cur表示1的个数
int first = 0, second = 0, third = 0, cur = 0;
for(int i = 0; i < n; i ++ )
{
if(arr[i] == 1)
{
cur ++ ;
if(cur == 1) first = i;
else if(cur == part + 1) second = i;
else if(cur == 2 * part + 1) third = i;
}
// [first, first+len-1], [second, second+len-1], [third, third+len-1]
// len = (n-1)-first+1
}
int len = n - 1 - third + 1;
cout << first << ' ' << second << ' ' << third << endl;
cout << len << endl;
for(int i = 0; i < len; i ++ )
{
if(first + i >= second || second + i >= third) return {-1, -1};
if(arr[first + i] != arr[second + i] || arr[second + i] != arr[third + i]) return {-1, -1};
}
return {first + len - 1, (second + len - 1) + 1};
}
};