Longest Increasing Subsequence (LIS) 問題,並使用二維串列來儲存和計算最長遞增子序列。以下是詳細的程式解釋。
程式邏輯解釋
函式定義與初始化
def lis(arr): n = len(arr) dp = [[i] for i in arr]
arr
是輸入的數列,例如[1, 3, 8, 5, 6, 7, 4, 9, 2]
。n
是數列的長度。dp
是一個二維串列,每個dp[i]
都初始化為[arr[i]]
,表示只包含當前元素的子序列。這意味著在最壞情況下,每個元素本身就是一個長度為1
的子序列。
填充
dp
表格for i in range(1, n): for j in range(0, i): if arr[j] < arr[i] and len(dp[j]) + 1 > len(dp[i]): dp[i] = dp[j] + [arr[i]]
- 使用雙重迴圈來比較元素:
- 外層迴圈
i
:從1
到n-1
,遍歷每個元素。 - 內層迴圈
j
:遍歷從0
到i-1
的所有元素。
- 外層迴圈
- 更新邏輯:
- 如果
arr[j] < arr[i]
,表示可以從j
延伸出一個遞增序列。 - 並且如果
dp[j]
的長度加1
大於dp[i]
的長度,則更新dp[i]
為dp[j] + [arr[i]]
,表示將arr[i]
添加到dp[j]
的序列中,形成更長的 LIS。 - 這樣做會保證每一個
dp[i]
都儲存從開頭到i
位置的最長遞增子序列。
- 如果
- 使用雙重迴圈來比較元素:
找出最長的 LIS
longest_lis = max(dp, key=len) return longest_lis, len(longest_lis)
- 使用
max(dp, key=len)
來找出dp
中長度最長的子序列。 - 返回最長的遞增子序列及其長度。
- 使用
測試程式碼
arr = [1, 3, 8, 5, 6, 7, 4, 9, 2] str1, len1 = lis(arr) print(str1, len1)
- 給定數列
arr = [1, 3, 8, 5, 6, 7, 4, 9, 2]
,調用lis
函式。 - 打印最長遞增子序列及其長度。
- 給定數列
執行結果:
[1, 3, 5, 6, 7, 9] 6
解釋:
- 初始化:
dp
初始為[[1], [3], [8], [5], [6], [7], [4], [9], [2]]
。 - 逐步更新
dp
:- 當
i = 2
(arr[2] = 8
) 時,j = 1
(arr[1] = 3
) 使得dp[2]
更新為[1, 3, 8]
。 - 當
i = 3
(arr[3] = 5
) 時,j = 1
(arr[1] = 3
) 使得dp[3]
更新為[1, 3, 5]
。 - 當
i = 5
(arr[5] = 7
) 時,j = 4
(arr[4] = 6
) 使得dp[5]
更新為[1, 3, 5, 6, 7]
。 - 最後,當
i = 7
(arr[7] = 9
) 時,j = 5
(arr[5] = 7
) 使得dp[7]
更新為[1, 3, 5, 6, 7, 9]
。
- 當
- 找出最長 LIS:在
dp
中長度最長的子序列是[1, 3, 5, 6, 7, 9]
,長度為6
。
總結:
- 使用二維
dp
:每個dp[i]
保存從開頭到i
位置的最長遞增子序列。 - 更新邏輯:透過比較前面所有的元素,動態更新
dp[i]
來找到新的 LIS。 - 時間複雜度:O(n²) 由於雙重迴圈的存在。
- 優點:可以直接得到實際的 LIS,而不需要另外反向追踪。
沒有留言:
張貼留言