HackerRank - almost-sorted-interval (思维)

本文介绍了一种O(n)的算法来解决区间合并问题,通过维护两个序列s1和s2,分别记录当前数字左侧已合并区间的最小值和最大值,以此判断是否可以继续合并。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:题意非常简单,给你n个数,范围都是1-n,问你这个序列中有多少个区间满足最小值在最左边,最大值在最右边

思路:想了一个下午。。好久没做题感觉要eat shit了。。

          假设我们从左往右扫过去,我们考虑维护两个序列以及它们的贡献值,一个为当前数字左边已合并区间的最小值,一个为当前数字左边已合并区间的最大值,设一个为s1,一个s2,那么比如我出一个样例为 1 2 4 3 5 

         合并的过程为,首先扫到1,把1添加进s1,s2,因为当前只有你一个所以最大最小值都是你了,当扫到2的时候,因为s1中的1比2小,所以最小值满足了条件,然后看最大值s2序列,也满足1<2,所以1和2是可以合并的,此时我们把序列s2中的1删除,放入2,因为考虑右边的数字往左合并的时候必须满足最大值要比2大,所以既然大于2,那么也就大于1,而对于s1序列中的1是不用删除的,因为考虑右边的数字往左合并的时候它可以合并到2这里,也可以合并到1这里,那么对于数字2的贡献值就要加上1的贡献值,此时答案就是1+2, 然后扫到4,由于同样满足上述的过程,所以此时s1有1,2,4 ,s2序列中有4,此时答案为1+2+3

           然后扫到3这个数字,由于3是比4要小的,所以3是显然不能和4合并在一起,所以我们要将4的贡献值-1,并且更新s1,把4弹出,放入3,同样的s2中的4要比3大,故不能合并,此时的s2应该有4,3两个元素,理由和s1中有多个的原因是雷同的,此时答案是1+2+3 +1 

   最后扫到5这个数字,由于满足3比5小,最小值满足条件,然后看s2中尾是3,满足3<5,故是可以合并的,此时对于5的贡献值就要加上3的贡献值,然后再看s2中的4,也满足4<5,故4和5也是可以合并在一起的,所以5的贡献值还要加上4的贡献值,此时答案为1+2+3+1+4 = 11 那么这道题大概的流程就是这样了,非常的神奇的一个O(n)的做法


#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
#define LL long long
vector<int> mins;
vector<int> maxs;
int a[maxn];
int num[maxn];
LL ans = 0;
void maintainmins(int i)
{
	if(mins.empty())
		mins.push_back(a[i]);
	else
	{
		int tmp = mins.back();
		while(tmp > a[i])
		{
			num[maxs.back()]--;
			if(!num[maxs.back()]) maxs.pop_back();
			mins.pop_back();
			if(mins.empty())break;
			tmp = mins.back();
		}
		mins.push_back(a[i]);
	}
}
void maintainmaxs(int i)
{
	int tmp = maxs.back();
	while(tmp < a[i])
	{
		num[a[i]]+=num[tmp];
		maxs.pop_back();
		if(maxs.empty())break;
		tmp = maxs.back();
	}
	maxs.push_back(a[i]);
	ans+=num[a[i]];
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=0;i<=n;i++)
		num[i]=1;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i = 1;i<=n;i++)
	{
		maintainmins(i);
		if(maxs.empty())
		{
			ans++;
			maxs.push_back(a[i]);
			continue;
		}
		maintainmaxs(i);
	}
	printf("%lld\n",ans);
	return 0;
}


Almost sorted interval

  HackerRank - almost-sorted-interval 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值