POJ3250从多个方面考虑同一问题

18 篇文章 0 订阅
8 篇文章 0 订阅

有很多的方法过这题,以下介绍三种方法,主要思路是将序列反转(其实不反转也没什么),然后去找第i个元素左边靠最右的比这个元素大的位置j,那么i-j+1就是第i个元素对应的解。
第一种方法:利用线段树动态更新,完成上部分的查询,复杂度O(nlogn)。

对线段树处理这类问题的方法就不详细说明了,想要了解的,看这篇文章

 

我的代码:


第二种方法:利用一个单调栈,栈内维护一个递减的区间,记录在此元素之前比其大的元素序列的下标。新的元素入队,如果栈顶元素大于这个入队元素,那么结果就加上这个元素的下标减去栈顶元素下标再减去1,否则栈顶元素出栈,以此类推。算法复杂度是O(n)的。

算法实现其实很简单,只要维护一个栈,用top表示栈顶下标就可以了。

 

我的代码:

 

第三种方法:利用并查集的思路直接做。记录r[i]表示第i个元素可以到达的最右边的下标,那么每次利用下面的方式压缩路径:
r[i]=i;
while(h[i]>h[r[i]+1])r[i]=r[r[i]+1];
细节处理看我的代码,算法复杂度是O(n*α(n))的。

 

我的代码:

 

三个算法比较:

对于第一个算法肯定是最慢的,毕竟O(nlogn)的时间复杂度加上线段树的较大常数,和下面两个O(n)或者近似O(n)的算法来比,会逊色很多。

从后两个算法运行时间上看,O(n*α(n))的第三种算法反而更快,可能是我单调栈常数太大了,或者我的序列反转过的原因。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值