最長的後續序列

任務是在給定的整數陣列中找到最長子序列的長度,使得子序列的所有元素按升序排序。例如, { 15,27,14,38,26,55,46,65,85}的最長增加子序列(LIS)的長度是 6 ,最長的子序列是 {15,27,38,55,65,85} 。再次,對於 {3,4, -1,0,6,2,3 } ,LIS 的長度為 4 ,子序列為 {-1,0,2,3} 。我們將使用動態程式設計來解決這個問題。

我們來看第二個例子:Item = {3, 4, -1, 0, 6, 2, 3}。我們首先採用與序列大小相同的陣列 dp 。如果我們包括原始序列的第 i 項,則 dp [i] 表示 LIS 的長度。在一開始我們知道,對於每個專案,至少最長的增長子序列的長度為 1 。這是通過考慮單個元素本身。所以我們用 1 初始化 dp 陣列。我們將有兩個變數 ij 。最初將是 1j 將是 0 。我們的陣列看起來像: **** **** **** **** **** **** **** **** **** ****

           3     4    -1     0     6     2     3
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Index` |  0  |  1  |  2  |  3  |  4  |  5  |  6  |
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Value` |  1  |  1  |  1  |  1  |  1  |  1  |  1  |
+-------+-----+-----+-----+-----+-----+-----+-----+
           j     i

陣列上方的數字代表我們序列的相應元素。我們的策略是:

if Item[i] > Item[j]
    dp[i] := dp[j] + 1

這意味著,如果在元件是比元件更大 Ĵ ,包含元件在 LIS 的長度 Ĵ ,將長度增加 1 ,如果我們包括元件在它。在我們的例子中,對於 i = 1j = 0Item [i] 大於 Item [j] 。所以 dp [i] = dp [j] + 1 。我們的陣列看起來像:

           3     4    -1     0     6     2     3
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Index` |  0  |  1  |  2  |  3  |  4  |  5  |  6  |
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Value` |  1  |  2  |  1  |  1  |  1  |  1  |  1  |
+-------+-----+-----+-----+-----+-----+-----+-----+
           j     i

在每一步,我們將 j 增加到 i ,然後將 j 重置為 0 並遞增 i 。現在, j 已到達 i ,所以我們將 i 增加到 2

           3     4    -1     0     6     2     3
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Index` |  0  |  1  |  2  |  3  |  4  |  5  |  6  |
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Value` |  1  |  2  |  1  |  1  |  1  |  1  |  1  |
+-------+-----+-----+-----+-----+-----+-----+-----+
           j           i

對於 i = 2j = 0Item [i] 不大於 Item [j] ,所以我們什麼都不做並且增加 j

           3     4    -1     0     6     2     3
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Index` |  0  |  1  |  2  |  3  |  4  |  5  |  6  |
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Value` |  1  |  2  |  1  |  1  |  1  |  1  |  1  |
+-------+-----+-----+-----+-----+-----+-----+-----+
                 j     i

對於 i = 2j = 1Item [i] 不大於 Item [j] ,所以我們什麼都不做,因為 j 已達到其極限,我們遞增 i 並將 j 重置為 0

           3     4    -1     0     6     2     3
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Index` |  0  |  1  |  2  |  3  |  4  |  5  |  6  |
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Value` |  1  |  2  |  1  |  1  |  1  |  1  |  1  |
+-------+-----+-----+-----+-----+-----+-----+-----+
           j                 i

對於 i = 3j = 0Item [i] 不大於 Item [j] ,所以我們什麼都不做並且增加 j

           3     4    -1     0     6     2     3
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Index` |  0  |  1  |  2  |  3  |  4  |  5  |  6  |
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Value` |  1  |  2  |  1  |  1  |  1  |  1  |  1  |
+-------+-----+-----+-----+-----+-----+-----+-----+
                 j           i

對於 i = 3j = 1Item [i] 不大於 Item [j] ,所以我們什麼都不做並且增加 j

           3     4    -1     0     6     2     3
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Index` |  0  |  1  |  2  |  3  |  4  |  5  |  6  |
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Value` |  1  |  2  |  1  |  1  |  1  |  1  |  1  |
+-------+-----+-----+-----+-----+-----+-----+-----+
                       j     i

對於 i = 3j = 2Item [i] 大於 Item [j] ,因此 dp [i] = dp [j] + 1 。之後,由於 j 已達到極限,我們再次將 j 重置為 0 並遞增 i

           3     4    -1     0     6     2     3
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Index` |  0  |  1  |  2  |  3  |  4  |  5  |  6  |
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Value` |  1  |  2  |  1  |  2  |  1  |  1  |  1  |
+-------+-----+-----+-----+-----+-----+-----+-----+
           j                       i

對於 i = 4j = 0Item [i] 大於 Item [j] ,因此 dp [i] = dp [j] + 1 。之後,我們增加 j

           3     4    -1     0     6     2     3
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Index` |  0  |  1  |  2  |  3  |  4  |  5  |  6  |
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Value` |  1  |  2  |  1  |  2  |  2  |  1  |  1  |
+-------+-----+-----+-----+-----+-----+-----+-----+
                 j                 i

對於 i = 4j = 1Item [i] 大於 Item [j] 。我們還可以注意到 dp [i] = dp [j] + 1 將為我們提供 3 ,這意味著如果我們將 LIS 用於 Item [j] 並使用它新增 Item [i] ,我們將獲得更好的 LIS { 3,4,6}比{3,6}之前。所以我們設定 dp [i] = dp [j] + 1 。然後我們增加 j

           3     4    -1     0     6     2     3
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Index` |  0  |  1  |  2  |  3  |  4  |  5  |  6  |
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Value` |  1  |  2  |  1  |  2  |  3  |  1  |  1  |
+-------+-----+-----+-----+-----+-----+-----+-----+
                       j           i

對於 i = 4j = 2Item [i] 大於 Item [j] 。但是對於這種情況,如果我們設定 dp [i] = dp [j] + 1 ,我們將得到 2 ,這是{-1,6}不是我們可以使用 Item 做的最好的{3,4,6} [我] 。所以我們放棄了這個。我們將為我們的策略新增一個條件,即:

if Item[i]>Item[j] and dp[i]<dp[j] + 1
    dp[i] := dp[j] + 1

我們增加 Ĵ1 。遵循這個策略,如果我們完成我們的 dp 陣列,它將如下所示:

           3     4    -1     0     6     2     3
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Index` |  0  |  1  |  2  |  3  |  4  |  5  |  6  |
+-------+-----+-----+-----+-----+-----+-----+-----+
| `Value` |  1  |  2  |  1  |  2  |  3  |  3  |  4  |
+-------+-----+-----+-----+-----+-----+-----+-----+
                                         j     i

現在我們將迭代這個陣列並找出最大值,這將是 LIS 的長度。我們的虛擬碼將是:

Procedure LISLength(Item):
n := Item.length
dp[] := new Array(n)
for i from 0  to n
    dp[i] := 1
end for
for i from 1 to n
    for j from 0 to i
        if Item[i]>Item[j] and dp[i]<dp[j] + 1
            dp[i] := dp[j] + 1
        end if
    end for
end for
l := -1
for i from 0 to n
    l := max(l, dp[i])
end for
Return l

該演算法的時間複雜度為 O(n²),其中 n 是序列的長度。

為了找出原始序列,我們需要向後迭代並將其與我們的長度匹配。程式是:

Procedure LIS(Item, dp, maxLength):
i := Item.length
while dp[i] is not equal to maxLength
    i := i - 1
end while
s = new Stack()
s.push(Item[i])
maxLength := maxLength - 1
current := Item[i]
while maxLength is not equal to 0
    i := i-1
    if dp[i] := maxLength and Item[i] < current
        current := Item[i]
        s.push(current)
        maxLength := maxLength - 1
    end if
end while
while s is not empty
    x := s.pop
    Print(s)
end while

該演算法的時間複雜度為:O(n)