tags:
- 简单
- 参考
- 数组
flag: green
style: summer
date: ‘2019-7-11’
1018.可被5整除的二进制前缀
一、题目
给定由若干 0 和 1 组成的数组 A。我们定义 N_i:从 A[0] 到 A[i] 的第 i 个子数组被解释为一个二进制数(从最高有效位到最低有效位)。
返回布尔值列表 answer,只有当 N_i 可以被 5 整除时,答案 answer[i] 为 true,否则为 false。
-
示例 1:
输入:[0,1,1]
输出:[true,false,false]
解释:
输入数字为 0, 01, 011;也就是十进制中的 0, 1, 3 。只有第一个数可以被 5 整除,因此 answer[0] 为真。 -
示例 2:
输入:[1,1,1]
输出:[false,false,false] -
示例 3:
输入:[0,1,1,1,1,1]
输出:[true,false,false,false,true,false] -
示例 4:
输入:[1,1,1,0,1]
输出:[false,false,false,false,false] -
提示:
1 <= A.length <= 30000
A[i] 为 0 或 1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-prefix-divisible-by-5
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、解答
- 大佬解法
//编译原理,有限状体自动机 DFA,O(n)
class Solution {
public List<Boolean> prefixesDivBy5(int[] A) {
List<Boolean> res = new ArrayList<>();
if (A.length < 1) return res;
int StateSet[][] = new int[][]{
{0, 1},
{2, 3},
{4, 0},
{1, 2},
{3, 4}
};
int state = 0;
for (int i = 0; i < A.length; i++) {
state = StateSet[state][A[i]]; //转换后的状态
if (state == 0) {
res.add(Boolean.TRUE);
} else {
res.add(Boolean.FALSE);
}
}
return res;
}
}
执行用时 :5 ms, 在所有 Java 提交中击败了92.49%的用户
内存消耗 :50.4 MB, 在所有 Java 提交中击败了36.02%的用户
- 另一种解法:
从头开始算出十进制,判断是否能被五整除吗?早就超过位数了。
那么自然的想到如果上一个数就能被5整除,再乘以2,当然也能被5整除,所以直接把它当做0不是很好?
同样的如果上一个数被5除余数是1,就可以把它当做1来看,自然地想到 pre=pre%5
最后发现了几个可以改进的地方,第一是没必要既赋 true,又赋 false,直接在初始化的时候赋 false,有需要的时候在赋 true 不是更好?
第二个是,计算机算除法是很浪费时间的,%5 那一段花费了大量的时间,不如做个表,直接查表余数,岂不是更好?
class Solution {
public:
vector<bool> prefixesDivBy5(vector<int>& A) {
vector<bool> res(A.size(),false);
int pre(0);
vector<int> what_five_divided = { 0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4 };
for (int i = 0; i < A.size(); i++)
{
pre = pre << 1;
pre += A[i];
if (what_five_divided[pre] == 0)
{
res[i] = true;
}
pre = what_five_divided[pre];
}
return res;
}
};
作者:yan-si-zai-shui-li-de-yu
链接:https://leetcode-cn.com/problems/two-sum/solution/zhe-dao-ti-mu-de-gai-jin-guo-cheng-by-yan-si-zai-s/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 第三种解法:
思路
[1,1,1,0,1]
第一步:[1] = 0*2+1 = 1; //被5取模=1
第二步:[1,1] = 1*2+1 = 3; //被5取模=3
第三步:[1,1,1] = 3*2+1 = 7; //被5取模=2
第四步:[1,1,1,0] = 7*2+0 = 14; //被5取模=4
第五步:[1,1,1,0,1] = 14*2+1 = 29; //被5取模=4
如果每步计算2的幂,结果会越来越大,java没有基本类型可以承受如此大的结果考虑采用每次结果的模进行计算
第一步:[1] = (0*2+1)%5 = 1; //被5取模=1
第二步:[1,1] = (1*2+1)%5 = 3; //被5取模=3
第三步:[1,1,1] = (3*2+1)%5 = 2; //被5取模=2
第四步:[1,1,1,0] = (2*2+0)%5 = 4; //被5取模=4
第五步:[1,1,1,0,1] = (4*2+1)%5 = 4; //被5取模=4
class Solution {
public List<Boolean> prefixesDivBy5(int[] A) {
List<Boolean> list = new ArrayList<>(A.length);
int mod = 0;
for(int i = 0;i<A.length;i++) {
mod = (mod << 1)%5 + (A[i] == 1 ? 1 : 0);
list.add(mod%5==0);
}
return list;
}
}
复杂度分析:
执行用时 :8 ms, 在所有 Java 提交中击败了39.42%的用户
内存消耗 :50.8 MB, 在所有 Java 提交中击败了31.85%的用户
作者:xiao-qiu-qiu
链接:https://leetcode-cn.com/problems/two-sum/solution/ke-bei-5-zheng-chu-de-er-jin-zhi-qian-zhui-by-xiao/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 我的解法
class Solution {
public List<Boolean> prefixesDivBy5(int[] A) {
//合法性检查
if (A.length == 0 || A == null) {
return null;
}
List<Boolean> ans = new ArrayList<Boolean>();
//遍历数组
int temp = 0;
for (int i : A ) {
for(int j = i; j >= 0; --j){
temp += A[j]*Math.pow(2,i-j);
}
if (temp % 5 == 0) {
ans.add(true);
}else{
ans.add(false);
}
temp = 0;
}
return ans;
}
}
卡死一个范例:
输入:[0,1,1,1,1,1]
输出:[true,false,false,false,true,false]
输出为:[true,false,false,false,false,true]