图解LeetCode——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] 为第三部分
  • 这3个部分所表示的二进制值相等

如果无法做到,就返回 [-1, -1]。 注意,在考虑每个部分所表示的二进制时,应当将其看作一个整体。例如,[1,1,0] 表示十进制中的 6,而不会是 3。此外,前导零也是被允许的,所以 [0,1,1] 和 [1,1] 表示相同的值。

二、示例

2.1> 示例 1:

【输入】arr = [1,0,1,0,1]
【输出】[0,3]

2.2> 示例 2:

【输入】arr = [1,1,0,1,1]
【输出】[-1,-1]

2.3> 示例 3:

【输入】arr = [1,1,0,0,1]
【输出】[0,2]

提示:

  • 3 <= arr.length <= 3 * 10^4
  • arr[i] 是 0 或 1

三、解题思路

根据题目描述,我们可以知道要将arr数组分成3份,并且对于这3份由01组成的二进制值要相同。因为是二进制,由0和1组成,所以,如果二进制相同的话,那么这3个分组中,1的个数一定是相同的。所以,以下图为例,我们统计出了一共有3个“1”,满足被3整除。所以,第一个条件就满足了。

“1”我们校验完毕之后,我们再来看看“0”。对于二进制来说,影响最终结果的其实是“1”后面的“0”的个数,(即:0001000000010相等的,但是0010001000就是不等的了)。那么我们可以推导出在arr数组中最后的那个“1”,它后面有多少个“0”,那么每个分组中的最后那个“1”后面就必须有相同数量的“0”。我们还是以下图为例,由于arr[7]是最后一个“1”,它后面只有1个“0”,那么根据上面我们描述的规律,就可以将数组 arr = [0,0,1,0,1,0,0,1,0] 拆分为[0,0,1,0][1,0][0,1,0]

然后,我们以最短分组长度为基准,从末尾开始校验每组中相对应位置的值是否相同,如果都相同,那么就满足了题目中所描述的“三等分”了。然后将[i, j]返回即可。

四、代码实现

class Solution {
    public int[] threeEqualParts(int[] arr) {
        // 用于记录每个“1”所在arr中的位置(index)
        int[] record = new int[arr.length + 1];
        int oneCount = 0;
        for (int i = 0; i < arr.length; i++) if (arr[i] == 1) record[++oneCount] = i;
        // 如果数组全是0的情况,固定返回[0, arr.length - 1]
        if (oneCount == 0) return new int[]{0, arr.length - 1}; 
        // 如果1的个数不能被平分,则表示无法平均分配
        if (oneCount % 3 != 0) return new int[]{-1, -1}; 
        // gn:每组1的个数   lzn:最后一组末尾0的个数
        int gn = oneCount / 3, lzn = arr.length - 1 - record[oneCount]; 
        // 如果每组末尾0的个数不足,则返回[-1,-1]
        if (record[gn * 2] - record[gn] < lzn || record[gn * 3] - record[gn * 2] < lzn) return new int[]{-1, -1}; 
        int tail1 = record[gn] + lzn, tail2 = record[gn * 2] + lzn, tail3 = record[gn * 3] + lzn,
                nums = Math.min(Math.min(tail1 + 1, tail2 - tail1), tail3 - tail2);
        int[] result = new int[]{tail1, tail2 + 1};
        while(nums-- > 0) {
            if (arr[tail1] != arr[tail2] || arr[tail1]!= arr[tail3] || arr[tail2] != arr[tail3]) return new int[]{-1, -1};
            tail1--; tail2--; tail3--;
        }
        return result;
    }
}

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。

更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值