[動態規劃系列] —— 區間DP

石子合併

stones描述n堆石子質量,每次能夠合併相鄰2堆石子,付出代價爲2堆石子質量之和,問n堆石子合併爲1堆石子的最小代價?

例如對於stone = [1, 3, 5, 2]返回22。python

考慮對於區間[i, j],有斷點k,則合併[i, j]的代價cost(i, j)爲sum(stone[i:j+1]) + cost(i, k) + cost(k+1, j)。對於sum(stone[i:j+1])咱們能夠使用前綴和作優化。優化

DP方案1:記憶化搜索逆向DP。code

def solution(stones):
    n, prefix_sum = len(stones), [0]*(n+1)
    for i in range(n): prefix_sum[i] = stones[i] + prefix_sum[i-1]
    memory = [[0]*n for _ in range(n)]

    def search(i, j):
        if i == j: return 0
        if memory[i][j]: return memory[i][j]
        minimun = float('inf')
        for k in range(i, j):
            minimun = min(minimun, search(i, k) + search(k+1, j) + prefix_sum[j] - prefix_sum[i-1])
            memory[i][j] = minimun
        return minimun

    return search(0, n-1)

DP方案2:枚舉區間正向DP。ip

def solution(stones):
    n = len(stones)
    prefix_sum = [0]*(n+1)
    for i in range(n): prefix_sum[i] = stones[i] + prefix_sum[i-1]
    status = [[0]*n for _ in range(n)]

    for length in range(2, n+1):
        for i in range(n-length+1):
            j = i + length - 1
            minimum = float('inf')
            for k in range(i, j):
                minimum = min(minimum, status[i][k] + status[k+1][j] + prefix_sum[j] - prefix_sum[i-1])
            status[i][j] = minimum

    return status[0][n-1]

最長有效括號

給定一個只包含 '('')' 的字符串,找出最長的包含有效括號的子串的長度。

例如對於'(()(()'返回2。leetcode

考慮對於區間[i, j],若是區間[i+1, j-1]是合法的且i,j處匹配,那麼status[i, j] = status[i+1, j-1] + 2;接着須要枚舉[i, j]內的區間,尋找兩個相鄰合法區間,取和最大值。例如對於")()())"中,只有枚舉[1, 4]中的區間,才能計算出status[1, 4] = 2 + 2 = 4。字符串

def solution(s):
    if not s: return 0
    n, ans = len(s), 0
    status = [[0]*n for _ in range(n)]

    for length in range(2, n+1):
        for i in range(n-length+1):
            j = i + length - 1
            if (length == 2 or status[i+1][j-1]) and (s[i], s[j]) == ('(', ')'):
                status[i][j] = status[i+1][j-1] + 2
            for k in range(i, j):
                if status[i][k] and status[k+1][j]:
                    status[i][j] = max(status[i][j], status[i][k] + status[k+1][j])
            ans = max(ans, status[i][j])

    return ans

注意:對該題目使用區間DP會超時,此處僅用此題舉例,讓讀者能夠驗證本身代碼的正確性。(最長合法括號子序列問題沒找到,該問題對'(()(()'是返回4的,是找合法子序列的長度,不是子串)get

相關文章
相關標籤/搜索