Uva1609:Boring的序列(有相当难度的好题!)

来源:互联网 发布:壁虎老师java百度云 编辑:程序博客网 时间:2024/06/01 08:34

这道题的意思是:给定一个序列,如果任意子序列里面都有至少一个不重复的元素(不重复是只在子序列里面是唯一的),那么我们就叫这个序列是不无聊的。我们需要检测一个序列是否满足这种性质。

这道题首先是有O(n^2)的解法的,枚举任意子区间然后判断,但是判断这个操作为O(n),我们需要将其降为O(1).方法是用滑动窗口来维护信息,并且时刻维护不重复元素的数量。当然这种方法很直观,但是效率太低。

考虑有没有O(NlogN)的算法呢?

接下来考虑一下动态规划呢?好像A[L][R]这样的结构也是决定了O(N^2)的复杂度。

最后考虑一下分治算法,怎么分治?我们分成两个子序列不是随便分的,要考虑分完之后我们完整的序列是不是满足这个性质,很显然加入两个子序列满足这个性质,那么完整序列不满足的唯一可能就是存在一个跨过中间的序列不满足这个性质,但是这样一来枚举这个中间序列的复杂度非常的高(O(N^2/4)),这还不如一开始的办法。我也是在这里卡住了。最后参考了一下解析:

我们不妨先确定整个序列是否满足这个条件,如果满足就一定可以找到一个a[p],a[p]是全局唯一,然后从p开始分成两部分。这样T(N) = T(N-p)+T(p)+O(寻找a[p])。然而问题又来了,最后p怎么找呢?如果寻找p的复杂度是O(n),那么极端情况下T(N) = T(N-1)+T(1)+O(N) = O(N^2).但是好像找到一个p肯定要至少n次。其实我们可以先预处理所有元素,找到每一个元素左右和他最近的元素的位置。这可以在O(n)的时间完成!然后从两边开始寻找这个p,每次检测一个元素在当前区间是不是唯一只要O(1),这样不管p在那里,最终的复杂度不会高于O(NlogN),极端情况甚至可能是O(N)!

最后怎么找p的左右区间?答案是用一个set从左往右遍历并保存即可。

总结:这道题还是有相当难度的,关键就在于找到一个p然后分治,而且p的找法也很特殊,说实话我是想不出这么巧妙的办法。也可以总结出来分治的关键是两点:如何分,如何治?先分后治,还是先治后分?这都是值得我们思考的问题!

def find_bound(a):    n = len(a)    window = {}    pos_left,pos_right = {},{}    for i,x in enumerate(a):        if x in window:            pos_left[i] = window[x]            pos_right[window[x]] = i             window.pop(x)#ensure the only ele in window        window[x] = i    return pos_left,pos_rightdef find_unique(a,bound_left,bound_right):    global pos_left,pos_right    def check(pos):# x is the position        left,right = 0,0        left = pos_left[pos] if pos in pos_left else -1        right = pos_right[pos]  if pos in pos_right else len(a)        return left<bound_left and right > bound_right    left,right = bound_left,bound_right    while left<=right:        if check(left):return left        elif check(right):return right        left+=1        right-=1    return Nonedef main(a,left,right):    global pos_left,pos_right    if left>=right:return True    pos = find_unique(a,left,right)    if pos==None:return False    else:        return main(a,left,pos-1) and main(a,pos+1,right)a  = [1,4,3,2,0,3,2,1,3]pos_left,pos_right = find_bound(a)print('no-boring' if main(a,0,len(a)-1) else 'boring')
0 0
原创粉丝点击