【leetcode】【2022/10/6】927. 三等分

问题描述:

  • 给定一个由 01 组成的数组 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,1,0] 表示十进制中的 6,而不会是 3,此外,前导零也是被允许的,所以 [0,1,1] 和 [1,1] 表示相同的值。

核心思路:

  • 纯模拟题,要做的就是分情况讨论,举例子讨论即可。
    • 例如 nums = [0, 0, 1, 0, 1, 0, 0, 1, 0]
    • 可以分成的三数组为 nums1=[0,0,1,0]nums2=[1, 0]nums3=[0,1,0]
    • 关键一:最后一个子数组 nums3 中末尾 0 的个数决定了其他子数组末尾 0 的个数。
    • 关键二:最短子数组 nums2 = 2 的长度会决定数组的真正长度。【也就是说 nums1nums3 只需要检验末尾 2 个长度即可知道三个子数组是否在二进制表示上保持一致,因为 nums1 中的前导零是不需要判断的】
  • 具体来说:
    • 遍历原数组用来维护 1 的索引数组 idx,用变量 cnt 来记录数组中 1 的个数。
    • cnt == 0,说明数组中全为 0,则任意返回值都可以。
    • cnt 不是 3 的倍数,则说明数组中 1 的个数不能均匀分配,返回 ans = {-1,-1} 即可。
    • 处理好前导情况后,idx[cnt/3] 是第一个数组中最后一个 1 的索引,idx[cnt/3*2] 是第二个数组中最后一个 1 的索引,idx[cnt/3*3] 是第三个数组中最后一个 1 的索引。
    • 同时用 zcnt = m-1-idx[cnt] 来记录最后一组中末尾 0 的个数,前面分析的时候已经提过了,最后一组中 0 的个数决定了其他子数组中末尾 0 的个数,因此 idx[cnt/3] + zcnt 就是第一个子数组的尾部。
    • 获得三个数组的尾部之后,再获得三个子数组的最小长度 len,然后三个数组从后往前比较 len 个数字即可知道三个数组是否在二进制表达上一致。
  • 该题虽然是困难题,但思路上并不难,只是要处理的情况比较多比较繁琐。
    • 上述思路和下述代码均是参考自同一题解,具体看参考内容。

代码实现:

class Solution
{
public:
    vector<int> threeEqualParts(vector<int>& arr)
    {
        int m = arr.size();
        vector<int> idx(m+1); // 1 的位置
        int cnt = 0;
        for(int i = 0; i < m; ++i) if(arr[i] == 1) idx[++cnt] = i;
        if(cnt == 0) return {0, m-1}; // case 1:数组全是0
        if(cnt % 3 != 0) return {-1, -1}; // case 2:1 的个数不能均匀分配
        int gcnt = cnt / 3, zcnt = m-1-idx[cnt]; // gcnt 代表每组中1的个数,zcnt 代表最后一组中末尾0的个数
        if(idx[gcnt*2] - idx[gcnt] < zcnt or idx[gcnt*3] - idx[gcnt*2] < zcnt) return {-1,-1}; // case 3:每组末尾0的个数不同
        int tail1 = idx[gcnt]+zcnt; // 组 1 的尾部
        int tail2 = idx[gcnt*2]+zcnt; // 组 2 的尾部
        int tail3 = idx[gcnt*3]+zcnt; // 组 3 的尾部
        int len = min(min(tail1+1, tail2-tail1), tail3-tail2); // 长度
        vector<int> ans = {tail1, tail2+1};
        while(len-- > 0)
        {
            if(arr[tail1] != arr[tail2] or arr[tail1] != arr[tail3] or arr[tail2] != arr[tail3]) return {-1, -1};
            --tail1, --tail2, --tail3;
        }
        return ans;
    }
};

参考内容:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值