算法小知识-----10.07----- 三等分

96 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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};
    }
}

image.png