给定由若干 0 和 1 组成的数组 A。我们定义 N_i:从 A[0] 到 A[i] 的第 i 个子数组被解释为一个二进制数(从最高有效位到最低有效位)。
返回布尔值列表 answer,只有当 N_i 可以被 5 整除时,答案 answer[i] 为 true,否则为 false。
题目不难理解,但是如果我们用暴力解法是肯定不行的,会超过int或者long的最大位数,所以我们就要换新的思路去解决问题。
我们发现,题目中只针对对5整除,那么我们知道,能把5整除的,只有末尾是0或者是5的数字,那么就好办了,我们只需要针对最后一位去运算就可以了。
举例来说:1025这个数字,我们已经知道1020是可以整除5的没有问题,那么要做的就是判断5是否可以整除5.
9998这个数字,9990是肯定可以整除5的,9995也是可以整除5的,那么我们应该将转换成10进制的9990剔除还是将9995剔除呢?
当然是都可以了。
我们的目的就是针对最后一位,不管数组怎么进行顺次组装成为二进制,我们转换成为十进制只有,都是只看最后一位的,说白了,只要将最接近这个转换之后的数字而不超过这个数字的5的最大倍数减去就可以了。
上面的1025,自然也可以剔除1025,剩下0,来让list.add(true)。
然后就来首先我们的程序:
思路如下:
- 我们要用一个变量num来存储,所有顺次相加之后的总和,做最后的取余运算。
- 将A[]的A[0]单独拿出来处理,如果是0,就直接add(true),如果是1,就继续下面的运算。
- 我们要明白2进制转换成10进制的本质。比如[1 1 1 1]->[8 4 2 1],[1 0 0 1]->[8 0 0 1]
- 除此之外,我们要注意到 [1,0,0,0]转换进制之后,每次遍历,1的存在都在进行着“升值”,它的价值从1->2->4->8,所以,我们要在顺次相加之前,对原有位数的价值去*2,而所遍历的当前位数,如果是0就算了,因为[1,0]的0价值就是0,而[1,1]的第二个1,价值是1,所以话说回来,如果我们要遍历的当前数字是1,就要额外进行+1.
- 前四步结束之后,我们只需要,对num加完的结果去对5取余做个判断就可以了。
代码如下:
class Solution {
public List<Boolean> prefixesDivBy5(int[] A) {
List<Boolean> list = new ArrayList<>();
if (A == null || A.length == 0) return list;
int num = A[0];
if (A[0] == 0) list.add(true);
else list.add(false);
for (int i = 1; i < A.length; i++) {
num = A[i] == 0 ? num * 2 : num * 2 + 1;
num = num % 5;
if (num == 0) {
list.add(true);
}
else list.add(false);
}
return list;
}
}