0
点赞
收藏
分享

微信扫一扫

力扣刷题4

前端王祖蓝 2022-04-14 阅读 87

一、前言

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今天才稍微懂一点线段树,预计这周会总结一下线段树的一些东西哦!

四、总结

总之,虽然是一个简单的题目,但是还是有很多可以拓展的地方,这也是我需要慢慢去学习的!加油啊!冲鸭!

举报

相关推荐

0 条评论