【2019.10.15】网课 Za
stack S
A[0] = +OO S.push(0)
for (i = 1 ~ N)
{
while (A[S.top()] < A[i])
S.pop()
L[i] = S.top()
S.push(i)
}
deque Q
for (i = 1 ~ N)
{
while (Q.empty() == false && A[Q.back()] > A[i])
Q.pop_back()
Q.push_back(i)
if (Q.front() < i - K + 1)
Q.pop_front()
if (i >= K)
min[i - K + 1, i] = A[Q.front()]
}
O(N)
deque Q
for (i = 1 ~ N)
{
while (Q.empty() == false && A[Q.back()] > A[i])
Q.pop_back()
Q.push_back(i)
if (Q.front() < i - K + 1)
Q.pop_front()
if (i >= K)
min[i - K + 1, i] = A[Q.front()]
}
O(N)
P3143
sort(A)
for (r = 1 ~ N)
{
while (A[r] - A[l] > K)
++l
Pre[r] = max(Pre[r - 1], r - l + 1)
}
for (l = N ~ 1)
{
while (A[r] - A[l] > K)
--r
Suf[l] = max(Suf[l + 1], r - l + 1)
}
for (i = 1 ~ N)
Ans max= Pre[i - 1] + Suf[i]
P
P1102
P2671
二分
1083借教室
1314 聪明的质检员
关押罪犯也可以二分
2680
1613
1081
归并排序
int A[N], T[N];
long long int solve(int l, int r)
{
if (l == r)
return 0LL;
int m = l + ((r - l) >> 1);
LL Ret = solve(l, m) + solve(m + 1, r);
for (int i = m + 1, j = 1, k = l - 1;i <= r;++i)
{
while (j <= m && A[j] <= A[i])
T[++k] = A[j++];
Ret += m - j + 1;
T[++k] = A[i];
}
for (int i = l;i <= r;++i)
A[i] = T[i];
return Ret;
}
单调栈
可以线性寻找一个元素左边(或右边)第一个满足某种条件的元素
比较常见的问题是:给定一个序列,对于每个数寻找其左边或 右边)第一个比它大(或比它小)的数
以寻找每个数左边第一个比它大的数为例
从右往左扫,维护一个栈,存储当前还没找到比它大的数的元素
可以发现栈中的元素有两个信息是单调的:下标和数值
下标单调是因为入栈顺序的原因
数值单调是因为,如果不单调的话会推出矛盾
那么每次可以让栈中一些元素找到比它大的元素,把它们从栈中删除。可以发现这些元素一定是栈顶的一部分。这么一番操作后, 数据结构的性质没有发生变化
每个元素被至多加入一次和删除一次,所以时间复杂度是线性的
two-pointer双指针法
大概是我之前搞过的尺取法?于是复习了一遍
• 双指针就是有两个指针a和b。这个方法目的一般是为了统计这样 的二元组的一些信息(比如数量、极值等)
• 这样的二元组可能描述了一些其他东西,比如说一个闭合区间
• 如果分析题目性质可以发现,一个指针向一个方向动,另一个指 针也只会单向移动,也就是所谓的“单调性”,那就可以用这个方 法,移动指针的时间复杂度也是线性的