一、前言
sheepice的刷力扣篇章,虽然现在比较忙,但是如果有空,且写到一些比较有启发的力扣题的时候希望能够发一点点题解,这些题解的灵感来源于我自己看了很多神犇的题解,真的会很有收获。
sheepice的博客地址:大家感兴趣也可以去里面,说不定能学到一点东西哦!
二、力扣的某“简单题”
这个题目其实说真的,刚开始觉得真的挺难的,然后看到是个简单题我就知道数据的范围肯定给的非常的小,果不其然,数据范围只给了50,哈哈哈,所以第一次做这个题目的时候,这不就是简单的暴力枚举的题目吧,因为这题是三叶姐给到的“-+”题,然后看了看,好家伙,居然有可能上升为一个困难题(三叶姐关于本题的解答),awsl,于是乎我觉得今天去学习一下线段树的基本东西!!
三、一题多解
①暴力哈希
这里其实可以很容易想到,把所有题目中给到的range范围中的数,直接存储下来,然后呢直接进行一次 [ l e f t , r i g h t ] [left, right] [left,right]区间的一个遍历,看看区间内的元素是否满足在区间之内就好了!
class Solution {
public:
map<int, int> nums;
bool isCovered(vector<vector<int>>& ranges, int left, int right) {
for(auto range : ranges) {
for(auto i = range[0]; i <= range[1]; i++) {
nums[i]++;
}
}
for(int i = left; i <= right; i++) {
if(!nums.count(i)) return false;
}
return true;
}
};
暴力解法的时间复杂度为 O ( N ) O(N) O(N),由于这里开了一个哈希表,所以空间复杂度为 O ( N ) O(N) O(N)。当然这里的数据因为比较小嘛,直接开一个常数的52一个数组去记录数字是否存在,空间复杂度就变成 O ( C ) O(C) O(C)了哈哈。
②差分数组加前缀和
关于差分的思想和前缀和的计算,相信很多同学已经会了,在此不多加赘述,那么这一题的差分思想在哪呢?其实就是我们去计算一个一个区间所存在数字的时候.先设置一个差分数组 d i f f [ 52 ] diff[52] diff[52],假设我们要计算区间 [ 1 , 10 ] [1,10] [1,10]之内,保证这之间的数都出现过也就不为0,那么我们只需要让 d i f f [ 1 ] + 1 diff[1]+1 diff[1]+1然后让 d i f f [ 11 ] − 1 diff[11]-1 diff[11]−1,之后对区间做一次前缀和我们可以发现区间 [ 1 , 10 ] [1,10] [1,10]内的 d i f f diff diff数组就会全部变成1,代表数字出现在区间内,这样虽然并没有大大的优化时间复杂度。但是我们不难发现,如果当题目所给的区间有重复的时候,我们是可以通过这样的方法去计算出每一个数字被重复的次数,也就是在整个区间里面重复出现了多少次,这个可能也对日后碰到这样的题目提供了一个非常不错的思路!
class Solution {
public:
int diff[52];
bool isCovered(vector<vector<int>>& ranges, int left, int right) {
for(auto range : ranges) {
diff[range[0]]++;
diff[range[1] + 1]--;
}
for(int i = 1; i < 52; i++) {
diff[i] += diff[i - 1];
}
for(int i = left; i <= right; i++) {
if(diff[i] <= 0) return false;
}
return true;
}
};
时间复杂度为 O ( N ) O(N) O(N),空间复杂度就变成 O ( C ) O(C) O(C)。
③树状数组
本题采用线状数组其实无非就是会和第二种解法一样,只不过在树状数组的add操作里面,每次加入的是代表此元素出现的次数,最后利用差分的思想,可以直接得到某元素出现的次数,其实和方法二大同小异,但是希望自己再练一遍树状数组,所以呢,就还是写了一遍代码。如果对树状数组不了解的同学,sheepice也写了一篇博客,仅供uu们进行参考.树状数组初探!!
class Solution {
public:
int n = 55;
int sum[55];
int lowbit(int x) {
return x & (-x);
}
void add(int index, int value) {
for(int i = index; i <= n - 1; i += lowbit(i)) {
sum[i] += value;
}
}
int query(int index) {
int ans = 0;
for(int i = index; i > 0; i -= lowbit(i)) {
ans += sum[i];
}
return ans;
}
bool isCovered(vector<vector<int>>& ranges, int left, int right) {
for(auto range : ranges) {
for(auto i = range[0]; i <= range[1]; i++) {
add(i, 1);
}
}
for(int i = left; i <= right; i++) {
if(query(i) - query(i - 1) <= 0) return false;
}
return true;
}
};
时间复杂度为 O ( N ) O(N) O(N),空间复杂度变成 O ( C ) O(C) O(C)。
④线段树
线段树应该是解决所有树状数组能够解决的一些相关问题,同时也是解决绝大部分的区间求和和查询的一个最有利的手段,有关线段树的学习,大家可以参考此篇:线段树和树状数组。本篇下面的代码仅供参考,因为sheepicce今天才稍微懂一点线段树,预计这周会总结一下线段树的一些东西哦!
四、总结
总之,虽然是一个简单的题目,但是还是有很多可以拓展的地方,这也是我需要慢慢去学习的!加油啊!冲鸭!