LeetCode周赛2021年5月9日

Posted 韩旭051

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode周赛2021年5月9日相关的知识,希望对你有一定的参考价值。

太久不写代码了
第一次有空 做LeetCode周赛 不是 下标越界 就是 暴力超时
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
或者是 明明很简单的题目 就是懒得写 比较麻烦 就不动手
在这里插入图片描述

看别人的分享 学习一下

第一题 活着的人 最多的年份

class Solution {
public:
    int yr[3000];
    int maximumPopulation(vector<vector<int>>& logs) {
        for (vector<int> log : logs) {
            int b = log[0];
            int d = log[1];
            for (int i = b; i < d; ++i) ++yr[i];
        }
        int ans = 1950;
        int m = 0;
        for (int i = 1950; i <= 2050; ++i) {
            if (yr[i] > m) {
                m = yr[i];
                ans = i;
            }
        }
        return ans;

    }
};

第二题就是双指针

class Solution {
public:
    int yr[3000];
    int maximumPopulation(vector<vector<int>>& logs) {
        for (vector<int> log : logs) {
            int b = log[0];
            int d = log[1];
            for (int i = b; i < d; ++i) ++yr[i];
        }
        int ans = 1950;
        int m = 0;
        for (int i = 1950; i <= 2050; ++i) {
            if (yr[i] > m) {
                m = yr[i];
                ans = i;
            }
        }
        return ans;

    }
};

第三题 空间换时间存储中间值 动态规划

class Solution {
public:
    int a[200001], stk[200001];
    int l[200001], r[200001];
    long long s[200001];
    int maxSumMinProduct(vector<int>& nums) {
        int n = (int )nums.size();
        for (int i = 0; i < n; i ++) {
            a[i + 1] = nums[i];
        }
        for (int i = 1; i <= n; i ++) s[i] = s[i - 1] + a[i];
        stk[0] = 0;
        int top = 0;
        long long ans = 0;
        for (int i = 1; i <= n; i ++) {
            while (top && a[stk[top]] >= a[i]) -- top;
            l[i] = stk[top] + 1;
            stk[++ top] = i;
        }
        top = 0; stk[0] = n + 1;
        for (int i = n; i >= 1; i --) {
            while (top && a[stk[top]] >= a[i]) -- top;
            r[i] = stk[top] - 1;
            ans = max(ans, 1LL * a[i] * (s[r[i]] - s[l[i] - 1]));
            stk[++ top] = i;
        }
        return ans % ((int )1e9 + 7);
    }
};

子数组最小乘积的最大值
🔗链接:link

🧠思路:这种题目属于基础的笛卡尔树的题目,但是这里我们换一种方式论述。

由于所有的值都是正整数,所以区间长度在最小值不变的情况下越大越好。
我们把这个数组按照最小值进行划分。
容易知道如果把当前的最小值作为答案区间的最小值,
取整个数组的话答案一定最大,
所以此时就可以用最小值和整个数组的和更新一次答案。
两个被分出来的数组由于跨出这个数组就会碰到一个比数组里面所有数都还要小的数字,
必然比划分之前的数组答案还要小,
所以这两个数组里面的答案只能在数组里面。

我们惊讶的发现这就是一个递归求解的问题。
由于每一次分割都会少一个值,
可以发现计算的次数就是数组长度。

现在只有最后一个问题:找到最小值所在的位置。
为了方便编写,我们可以考虑使用 ST 表进行维护。
假如你知道怎么用 ST 表求出区间最小值,
那么我们只需要在去求完之后判断两个数字哪个更小,
使用这个方式进行更新即可。

作者:tiger2005
链接:https://leetcode-cn.com/circle/discuss/7QlTIV/view/Vo980u/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution {
public:
    int st[100010][20],st2[100010][20];
    int LOG2[100010];
    vector<int> n;
    vector<long long> m;
    int que(int l,int r){
        int m=LOG2[r-l+1];
        int ll=st2[l][m], rr=st2[r-(1<<m)+1][m];
        if(n[ll]<n[rr]) return ll;
        return rr;
    }
    long long ans=0;
    void dfs(int l,int r){
        if(l>r) return;
        if(l==r){
            ans=max(ans, 1ll*n[l] * n[l]);
            return;
        }
        int p=que(l, r);
        ans=max(ans, 1ll * n[p] * (m[r]-(l==0?0:m[l-1])));
        dfs(l,p-1);dfs(p+1,r);
    }
    int maxSumMinProduct(vector<int>& nums) {
        LOG2[1]=0;n=nums;
        m.resize(nums.size());
        m[0]=nums[0];
        for(int i=1;i<(int)nums.size();i++)
            m[i]=m[i-1]+nums[i];
        for(int i=2;i<=1e5;i++) LOG2[i]=LOG2[i>>1]+1;
        for(int i=0;i<(int)nums.size();i++)
            st[i][0]=nums[i],st2[i][0]=i;
        for(int i=1;(1<<i)<=(int)nums.size();i++)
            for(int j=0;j+(1<<i)<=nums.size();j++){
                st[j][i]=min(st[j][i-1], st[j+(1<<(i-1))][i-1]);
                if(st[j][i] == st[j][i-1])  st2[j][i]=st2[j][i-1];
                else    st2[j][i]=st2[j+(1<<(i-1))][i-1];
            }
        dfs(0, nums.size()-1);
        return ans % (1000000007);
    }
};

作者:tiger2005
链接:https://leetcode-cn.com/circle/discuss/7QlTIV/view/Vo980u/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

前缀和+单调栈
经典单调栈题目。因为数组元素都为正数,所以子数组最小值的元素位置一定时,子数组长度越大,得到的乘积越大。

我们利用单调栈可以求出每个元素作为最小值时的最长子数组,再利用预计算的前缀和求得乘积。最后取所有乘积的最大值即可。

时间复杂度\\mathcal{O}(N)O(N)。
空间复杂度\\mathcal{O}(N)O(N)。

using ll = long long;
const ll MOD = 1e9 + 7;

class Solution {
public:
    int maxSumMinProduct(vector<int>& nums) {
        int n = nums.size();
        vector<ll> s(n + 1);
        for (int i = 1; i <= n; ++i)
            s[i] = s[i - 1] + nums[i - 1];
        
        vector<int> l(n, 0), r(n, n - 1);
        stack<int> st;
        for (int i = 0; i < n; ++i) {
            while (!st.empty() && nums[st.top()] > nums[i]) {
                r[st.top()] = i - 1;
                st.pop();
            }
            st.push(i);
        }
        st = stack<int>();
        for (int i = n - 1; i >= 0; --i) {
            while (!st.empty() && nums[st.top()] > nums[i]) {
                l[st.top()] = i + 1;
                st.pop();
            }
            st.push(i);
        }
        
        ll ans = 0;
        for (int i = 0; i < n; ++i)
            ans = max(ans, (s[r[i] + 1] - s[l[i]]) * nums[i]);
        
        return ans % MOD;
    }
};

作者:吴自华
链接:https://leetcode-cn.com/circle/discuss/7QlTIV/view/2CLPG9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

最后一题完全没看 就没有学习价值了 我就 只摘抄前三题

以上是关于LeetCode周赛2021年5月9日的主要内容,如果未能解决你的问题,请参考以下文章

;~ 小部分AutoHotkey源代码片段测试模板2019年10月9日.ahk

Leetcode周赛从contest-71开始。(一般是10个contest写一篇文章)

Leetcode周赛从contest-121开始。(一般是10个contest写一篇文章)

2021年5月9日,是第108个母亲节,祝福所有的母亲节日快乐

LeetCode第 30 场双周赛题解

leetcode练习笔记2022年9月