最長上升子序列
最長上升子序列(Longest Increasing Subsequence,LIS)是一個在數列中尋找最長的元素序列的問題,其中每個元素都比其前一個元素大。例如,對於數列 [2, 10, 4, 7, 1, 5]
,最長上升子序列是 [1, 2, 4, 5]
,因為它是所有可能的上升子序列中最長的一個。
最長上升子序列問題可以用 Dynamic Programming 來解決,時間複雜度為 O(n^2),空間複雜度為 O(n)。以下是解決這個問題的一個簡單算法:
- 初始化一個長度為 n 的數組
dp
,其中dp[i]
表示數列中前 i 個元素的最長上升子序列的長度。 - 初始化一個長度為 n 的數組
lis
,其中lis[i]
表示數列中前 i 個元素的最長上升子序列的起始位置。 - 對於每個元素
nums[i]
,檢查它是否可以作為最長上升子序列的終點。如果nums[i]
比nums[lis[dp[i-1]]]
大,那麼dp[i]
就等於dp[i-1] + 1
,並且lis[dp[i]] = i
。否則,dp[i]
就等於dp[lis[dp[i]]]
。 - 最後,最長上升子序列的長度就是
dp[n-1]
,而最長上升子序列本身則可以通過lis[0..dp[n-1]-1]
來獲取。
以下是一個簡單的 Python 實現:
def lis(nums):
n = len(nums)
dp = [1] * n # 初始化 dp[i] 為 1,表示以 nums[i] 結尾的最長上升子序列的長度為 1
lis = [0] * n # 初始化 lis[i] 為 0,表示以 nums[i] 結尾的最長上升子序列的起始位置為 0
for i in range(n):
for j in range(i):
if nums[i] > nums[j] and dp[i] < dp[j] + 1:
dp[i] = dp[j] + 1
lis[i] = j
return dp[-1], lis
# 示例
nums = [2, 10, 4, 7, 1, 5]
length, lis = lis(nums)
print(length) # 輸出最長上升子序列的長度
print(lis) # 輸出最長上升子序列的起始位置
這個算法的時間複雜度為 O(n^2),因為每一個 dp[i]
都需要檢查 O(n) 次。空間複雜度為 O(n),因為我們只需要額外的一個數組 dp
和 lis
來存儲狀態。
對於某些特定的數列,可能存在更高效的算法來解決最長上升子序列問題,例如對於隨機數列,可以使用二分查找來降低時間複雜度到 O(n log n)。但是,對於一般的數列,上述的動態規劃算法是最常用的解決方法。