持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情
国庆最后一天了,这不得挑战一下自己的软肋,人生中的第7道困难题
三等分
该题出自力扣的927题 —— 三等分【困难题】
审题
给定一个由 0 和 1 组成的数组 arr ,将数组分成 3 个非空的部分 ,使得所有这些部分表示相同的二进制值。 如果可以做到,请返回任何 [i, j],其中 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, -1]。
- 这是一道困难题,那么就需要全力以赴,但是又比其他奇怪的困难题要来得题意简单
- 其实就是给出一个整型数组,要求分成三个部分,每个部分的二进制值是一样的,包括前导零。其次数组内只包含1和0两种数字
- 那么可以先进行两个剪枝,先对数组进行求和,那么如果和结果为0,就证明一个1都没有,那么就可以随便分3个区间了,直接返回[0,2]
- 如果数组总和 不能被3整除,就证明1的出现个数不能均分3份,自然也就输出[-1,-1]
- 该题的核心就在于,从最后的区间开始确定,最后区间的后导零才能决定所有区间的后导零。
- 剩余的其他位顺序要相同
编码
class Solution {
public int[] threeEqualParts(int[] arr) {
int sum=0;
for(int i=0;i<arr.length;i++){sum+=arr[i];}
if(sum==0){return new int[]{0,2};}
if(sum%3!=0){return new int[]{-1,-1};}
sum/=3;
int r=arr.length-1,l=0;
while(arr[r]==0){r--;}
int end=r;
int zero=arr.length-1-r;//最后一个数末尾0的个数,其他俩数的末尾0应该不少
int count=0;
while(count<sum){
count+=arr[l];
l++;
}
//此时的l是第一组1的末尾后边
r=l;
while(count<sum*2){
count+=arr[r];
r++;
}
//此时的r是第二组1的末尾后边
//先验证末尾0是否数量足够:
for(int i=l;i<l+zero;i++){if(arr[i]==1){return new int[]{-1,-1};}}
for(int i=r;i<r+zero;i++){if(arr[i]==1){return new int[]{-1,-1};}}
//再验证其他位是否一致:
count=0;
for(int i=0;count<sum;i++){
if(arr[end-i]!=arr[r-1-i]||arr[end-i]!=arr[l-1-i]){return new int[]{-1,-1};}
count+=arr[end-i];
}
return new int[]{l+zero-1,r+zero};
}
}