太久不写代码了

第一次有空 做LeetCode周赛 不是 下标越界 就是 暴力超时

LeetCode周赛2021年5月9日_i++

LeetCode周赛2021年5月9日_i++_02

LeetCode周赛2021年5月9日_数组_03

或者是 明明很简单的题目 就是懒得写 比较麻烦 就不动手

LeetCode周赛2021年5月9日_数组_04

看别人的分享 学习一下

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

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

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

前缀和+单调栈

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

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

时间复杂度\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;
}
};

作者:吴自华

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