有很多的方法过这题,以下介绍三种方法,主要思路是将序列反转(其实不反转也没什么),然后去找第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))的第三种算法反而更快,可能是我单调栈常数太大了,或者我的序列反转过的原因。