单调栈 + dp
dp蛮好想的
单调栈需要注意,此题要求i由j转移而得的条件为:
1. j == i - 1
2. i, j位置的h较小值必须大于二者之间序列内的最大值
3. i, j位置的h较大值必须小于二者之间序列内的最小值
满足任意一条即可转移
而 对于相同高度的元素,则不能同时出现在栈内。因为当后续节点由此部分节点进行转移时,相同高度的前一个元素是不能进行转移的。
因而必须判断,当即将加入栈内的元素与栈顶元素高度相同时,则需要将i位置的dp更新,之后将原先的栈顶元素弹出,再将新的具有相同高度的i节点加入栈中。
这也与栈的单调性保持了一致。
1 #include<iostream>
2 #include<algorithm>
3 #include<cstring>
4 #include<cmath>
5 #include<stack>
6 #include<cstdio>
7 #define INF 0x3f3f3f3f
8 using namespace std;
9 const int N = 3e5 + 10;
10
11 int n;
12 int a[N];
13 int dp[N];
14
15 int read(){
16 char ch=getchar();int x=0,f=1;
17 while(ch<'0' || ch>'9') {if(ch=='-')f=-1;ch=getchar();}
18 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
19 return x*f;
20 }
21 stack<int> s1, s2;//up, down
22 int main(){
23 n = read();
24 for(register int i = 1 ; i <= n ; i++){
25 a[i] = read();
26 dp[i] = INF;
27 }
28 dp[1] = 0;
29 s1.push(1);
30 s2.push(1);
31 for(register int i = 2 ; i <= n ; i++){
32 //递减栈
33 while(!s1.empty() && a[s1.top()] < a[i]){
34 dp[i] = min(dp[i], dp[s1.top()] + 1);
35 s1.pop();
36 }
37 if(int(s1.size())){
38 dp[i] = min(dp[i], dp[s1.top()] + 1);
39 if(a[i] == a[s1.top()]){//严格保持栈的单调性
40 s1.pop();
41 //若存在两个相同高度的块,后更新dp实际上不可更新前一个高度 4 3 3 : i = 2 ?只能更新后面那个3
42 }
43 }
44 s1.push(i);
45
46 //递增栈
47 while(!s2.empty() && a[s2.top()] > a[i]){
48 dp[i] = min(dp[i], dp[s2.top()] + 1);
49 s2.pop();
50 }
51 if(int(s2.size())){
52 dp[i] = min(dp[i], dp[s2.top()] + 1);
53 if(a[i] == a[s2.top()]){
54 s2.pop();
55 }
56 }
57 s2.push(i);
58 }
59 printf("%d
",dp[n]);
60
61 return 0;
62 }