这题可用树状数组来解:力扣1893
什么是树状数组
定义有点小多,
参照这篇文章树状数组 数据结构详解与模板,看前面的介绍即可;
树状数组干啥的
经过巧妙复杂的数据结构,可以以O(lgN)的复杂度获得动态数组的前缀和(不用这个结构的话,动态更新数组,计算前缀和需要O(n)的复杂度),原因参照定义;
//树状数组的实现代码,lowbit,update,query是一定要实现的
//new 一个树状数组
int n = 51;
int[] tree = new int[n];
//输出i的2进制数最后一位1所在位置的大小
int lowbit(int i){
return i&(-i);
}
//动态更新树状数组 复杂度O(lgN)
void update(int index,int v){
for(int i=index; i<n; i+=lowbit(i)){
tree[i] += v;
}
}
//获取树状数组前缀和 复杂度O(lgN)
int query(int index){
int ans = 0;
for(int i=index; i>0; i-=lowbit(i)){
ans += tree[i];
}
return ans;
}
说说lowbit方法
该方法的功能是返回一个数二进制最低位1所在位置的大小;
举个栗子,
- 3的二进制11,输入lowbit返回的是1->二进制1
- 6的二进制110,输入lowbit返回的是2->二进制10
- 12的二进制1100,输入lowbit返回的是4->二进制100
那为什么**i&(-i)**就能等得到最低位1呢?
因为利用了负数补码的原理,负数要取反加一。一个数经过取反加一操作后,最后一位1还是1,其它位全部相反。所以i&(-i)得到的是最低位1的大小;
举个栗子,
数字6的二进制110,
取反加一后成为010
只有最后一位1是不变的。
完整题解
class Solution {
int n = 51;
int[] tree = new int[n];
int lowbit(int i){
return i&(-i);
}
void update(int index,int v){
for(int i=index; i<n; i+=lowbit(i)){
tree[i] += v;
}
}
int query(int index){
int ans = 0;
for(int i=index; i>0; i-=lowbit(i)){
ans += tree[i];
}
return ans;
}
public boolean isCovered(int[][] ranges, int left, int right) {
Set<Integer> set = new HashSet<>();
for(int[] range:ranges){
for(int l=range[0]; l<=range[1]; l++){
if(!set.contains(l)){
update(l,1);
set.add(l);
}
}
}
return query(right)-query(left-1) == right-left+1;
}
}