刪除子序列問題

給定一個序列,要求從裏面刪除一個連續的子序列,使得剩下的序列裏含有一個最長的連續遞增子序列。

這個題目有O(nlogn)的解法,但是比較複雜,我也沒有研究清楚,就先說O(n^2)的算法吧:

最容易想到的是枚舉算法(i,j),然後檢測能夠拼接的最長子序列。當然檢測這個步驟需要O(n),我們有兩種方式來解決這個問題.

(1)預處理計算出所有的f(i),g(i),f(i)代表以第i個元素結束的遞增序列,g(i)代表以第i個元素開始的遞增序列,這就是一個最長子序列問題,直接動態規劃O(N)可解。後面就比較簡單了:

def start_length(s):
    n = len(s)
    f = [1]*len(s)
    for i in range(n-2,-1,-1):
        if s[i] < s[i+1]:
            f[i] = f[i+1] + 1
    return f
def end_length(s):
    n = len(s)
    G = [1]*n
    for i in range(1,n):
        if s[i-1]<s[i]:
            G[i] = G[i-1]+1
    return G
def find_seq(s):
    m = 0
    n = len(s)
    F,G = start_length(s),end_length(s)
    print(F,G)
    for i in range(1,n):
        for j in range(i,n-1):
            if s[i-1] <s[j+1]:
                m = max(m,G[i-1]+F[j+1])
    print(m)

(2)這個辦法沒有上一個好,但是還是說一下,利用滑動窗口的思想來做,我們的目的是計算的時候能夠迅速得出左右的子序列的長度,所以就需要維護兩個遞增的子序列,當左邊新進來的元素不能保證遞增的序列時,我們要將左邊的隊列清空再入隊。右邊的隊列也始終保持一個單調遞增的性質,每次枚舉j,就將右邊的隊列出隊一個元素,並且如果隊列爲空則需要繼續尋找一次。

def growth_seq(s,g,i):
    n = len(s)
    i+=1
    while i < n and (len(g)==0 or g[-1]<s[i]):
        g.append(s[i])
        i+=1

def find_seq2(s):
    n = len(s)
    m = 0
    left = deque()
    left.append(s[0])

    for i in range(1,n):
        right = deque()
        while j<n-1:
            if len(right)==0:
                growth_seq(s,right,j)

            if s[i-1]<s[j+1]:
                m = max(m,len(left)+len(right))

            right.popleft()

        while len(left) and left[-1] > s[i]:
            left.pop()
        left.append(s[i])
    print(m)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章