题目链接:Problem - C - Codeforces
题意:给出一个数组,如果I < j 并且arr[i] > arr[j],就可以将i和j连接起来形成无向图,求最终有多少个没联通的部分。
思路:
求有多少个未联通的部分,所以我们只要把可以联通的部分联通起来就可以了,但是这样的时间复杂度是O(n^2),然后发现其实有许多联通是不必要的,所以就考虑用什么方法合适的连接可以连接的点。
因为一个数只和后面比小的数有连接,所以这里建立一个单调递增的栈来进行操作。
那么就有两种情况:
- 新数大于栈顶,不会和栈里面的数连接,所以直接放入到栈中
- 遇到一个新数小于栈顶的话,它会和当前的栈顶连接,所以这里是不断判断,如果新数小于栈顶就将数push出栈顶,因为push出来的所有数都是可以和当前数连接的,然后贪心(数越大越有可能和后面的数连接)保留最大数放回栈中。
这样最后栈里面的数就是答案
比如
5
3 1 5 2 4
3 入栈
1比3小,3出栈,最大数为3,3入栈。
5比3大,5入栈
2比5小,5出栈,2 也比3小,3出栈,3和5比大数为5,5入栈
4比5小,5出栈,大数为5,5入栈
最终栈中只有一个元素为5,所以答案为栈的大小1
#include <stdio.h>
#include <stack>
using namespace std;
int a[200005];
stack<int> s;
int main()
{
int _, i, n;
scanf("%d", &_);
while (_--)
{
//初始化
while (!s.empty())
s.pop();
scanf("%d", &n);
for (i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (i = 1; i <= n; i++)
{
if (s.empty() || a[i] > s.top())
{
s.push(a[i]);
continue;
}
//记录最大值
int maxn = 0;
while (!s.empty() && s.top() > a[i])
{
maxn = max(maxn, s.top());
s.pop();
}
s.push(maxn);
}
printf("%d\n", s.size());
}
return 0;
}