LeetCode每日一题(Three Equal Parts)

You are given an array arr which consists of only zeros and ones, divide the array into three non-empty parts such that all of these parts represent the same binary value.

If it is possible, return any [i, j] with i + 1 < j, such that:

  • arr[0], arr[1], ..., arr[i] is the first part,
  • arr[i + 1], arr[i + 2], ..., arr[j - 1] is the second part, and
  • arr[j], arr[j + 1], ..., arr[arr.length - 1] is the third part.
  • All three parts have equal binary values.

If it is not possible, return [-1, -1].

Note that the entire part is used when considering what binary value it represents. For example, [1,1,0] represents 6 in decimal, not 3. Also, leading zeros are allowed, so [0,1,1] and [1,1] represent the same value.

Example 1:

Input: arr = [1,0,1,0,1]
Output: [0,3]

Example 2:

Input: arr = [1,1,0,1,1]
Output: [-1,-1]

Example 3:

Input: arr = [1,1,0,0,1]
Output: [0,2]

Constraints:

  • 3 <= arr.length <= 3 * 104
  • arr[i] is 0 or 1

不得不说其实很讨厌做这种题, 不是说思考的时候有多难,而是实现的时候要像放贼一样防着各种特殊情况。

整体思路是如果一个数组可以被分成三个相等的部分,那一定要满足以下3个条件:

1. 整个数组里的1的数量一定是3的倍数, 且分到每个部分里面1的数量一定是一样的

2. 每个部分里面从第一个1到最后一个1这个切片,每个部分都是一样的

3. 每个部分的后缀0的数量一定与最后一部分的后缀0的数量是一致的

三个条件全部满足则能分,有一个不满足则不能分。

具体的方法是把数组分成几个部分,  下面来个例子:

[0 --- 0 --- 0 --- 1 --- 0 --- 1 --- 0 --- 0 --- 0 --- 1 --- 0 --- 1 --- 0 --- 0 --- 0 --- 1 --- 0 --- 1 --- 0 --- 0 ---0]

                        |               |                             |              |                              |              |

                       S1---------E1                          S2--------E2                           S3---------E3

                        |-----F1-----|                            |-----F2---|                              |-----F3----|

不会画图,大家凑或着看吧。Fi为每一部分从第一个1到最后一个1的切片, Si为Fi的起始索引, Ei为Fi的终止索引。F1、F2、F3这三段一定是完全一样的。然后再来看后置0的情况, 因为前置0没有意义所以我们可以任意分割Fi之间的0, 以保证前段后置0达到我们所需的数量。但是首先我们得看到, 从E3到数组结尾的0, 也就是F3的后置0的数量我们是没法改变的, 也就是说前面F1、F2的后置0的数量一定要有能力能跟F3的后置0的数量一致,我们才能把数组'等分'。但就像我们前面所说的,前置0没有意义,而中间的那些0段我们可以任意分割成两段, 前半段作为Fi的后置0,后半段作为Fi+1的前置0, 所以我们可以得出, 只要E1到S2之间的0的数量和E2到S3之间的0的数量大于等于E3到数组末尾的0的数量就可以实现'等分'。但是这里面要考虑数组全都是0的情况和有3个1的情况, 这两种情况单独处理一下就好。

具体实现如下(Rust):

impl Solution {
    pub fn three_equal_parts(arr: Vec<i32>) -> Vec<i32> {
        let ones = arr.iter().filter(|&&v| v == 1).count();
        if ones == 0 {
            return vec![0, arr.len() as i32 - 1];
        }
        if ones % 3 != 0 {
            return vec![-1, -1];
        }
        let factor = ones / 3;
        let (mut s1, mut e1, mut s2, mut e2, mut s3, mut e3) = (0, 0, 0, 0, 0, 0);
        let mut count = 0;
        for i in 0..arr.len() {
            if arr[i] == 1 {
                count += 1;
                match count {
                    1 => {
                        s1 = i;
                        if factor == 1 {
                            e1 = i;
                        }
                    }
                    c if c == factor => e1 = i,
                    c if c == factor + 1 => {
                        s2 = i;
                        if factor == 1 {
                            e2 = i;
                        }
                    }
                    c if c == factor * 2 => e2 = i,
                    c if c == factor * 2 + 1 => {
                        s3 = i;
                        if factor == 1 {
                            e3 = i;
                        }
                    }
                    c if c == factor * 3 => e3 = i,
                    _ => {}
                }
            }
        }
        for ((v1, v2), v3) in arr[s1..e1 + 1]
            .iter()
            .zip(arr[s2..e2 + 1].iter())
            .zip(arr[s3..e3 + 1].iter())
        {
            if v1 != v2 || v2 != v3 {
                return vec![-1, -1];
            }
        }
        let tail_zero = arr.len() - 1 - e3;
        if s2 - e1 - 1 < tail_zero || s3 - e2 - 1 < tail_zero {
            return vec![-1, -1];
        }
        vec![(e1 + tail_zero) as i32, (e2 + tail_zero + 1) as i32]
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值