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,而不需要另外反向追踪。
沒有留言:
張貼留言