持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情
刷题的日常-2022年10月6号
一天一题,保持脑子清爽
三等分
来自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]为第三部分。
- 这三个部分所表示的二进制值相等。
如果无法做到,就返回[-1, -1]。
注意,在考虑每个部分所表示的二进制时,应当将其看作一个整体。例如,[1,1,0]表示十进制中的6,而不会是3。此外,前导零也是被允许的,所以[0,1,1] 和[1,1]表示相同的值。
理解题意
我们可以从题意中提取的条件如下:
- 题目给出一个由 0 1 组成的数组
- 要求我们返回将数组进行三等分
- 要求每个等分的部分的二进制表示都一致
做题思路
从题意中可以发现,如果三等分要能够匹配,那么它们的1的个数一定要一致,所以1的总数要能被3整除。还有的是,前导零对我们没影响,但是后导零是有的。仔细查看可以发现,最后一部分的后导零是没办法消除的,所以找到最后一位开始的位置,我们就可以知道分割出来的数应该是什么样子的。步骤如下:
- 统计1的个数
- 如果不能被3整除,直接返回。需要注意的是,如果全是0,那么怎么分割都是对的,这里直接返回前后指针就可以了
- 查找每部分的开始位置
- 由最后一部分往后扫描,如果全部匹配,就返回最后的索引位置
- 不能匹配则返回-1
代码实现
代码实现如下:
public class Solution {
public int[] threeEqualParts(int... arr) {
int[] idx = new int[]{-1, -1, -1};
int len = 0, cnt = 0, dev = -1;
for (int num : arr) {
len += num;
}
if (len == 0) {
return new int[]{0, arr.length - 1};
}
if (len % 3 != 0) {
return new int[]{-1, -1};
}
len /= 3;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 0) {
continue;
}
cnt += arr[i];
if (cnt == 1) {
dev++;
}
cnt %= len;
idx[dev] = idx[dev] == -1 ? i : idx[dev];
if (dev == 2) {
break;
}
}
while (idx[2] < arr.length) {
if (arr[idx[0]] != arr[idx[1]] || arr[idx[0]] != arr[idx[2]]) {
return new int[]{-1, -1};
}
idx[0]++;
idx[1]++;
idx[2]++;
}
return new int[]{idx[0] - 1, idx[1]};
}
}