📅  最后修改于: 2023-12-03 15:40:17.523000             🧑  作者: Mango
在一个数组中,最长递增子序列指的是一个子序列中,所有元素都是递增的,并且长度尽可能地长。
例如,在数组 [10, 9, 2, 5, 3, 7, 101, 18] 中,最长递增子序列是 [2, 3, 7, 101],长度为 4。
本文将介绍一些解决这个问题的算法。
我们可以使用动态规划算法来解决这个问题。
首先,我们用一个一维数组 dp
来表示以每个元素为结尾的最长递增子序列的长度。初始值被全部初始化为 1,因为每个元素都可以单独构成一个子序列。
接着,我们枚举数组中的每个元素 i,然后再次枚举 j,其中 0 <= j < i。如果 nums[j] < nums[i],那么 nums[i] 可以接在 nums[j] 的后面形成一个更长的递增子序列。因此,我们可以得出转移方程:
dp[i] = max(dp[i], dp[j] + 1)
最终的答案是数组 dp
中的最大值。
代码如下:
def lengthOfLIS(nums):
if not nums:
return 0
n = len(nums)
dp = [1] * n
for i in range(1, n):
for j in range(i):
if nums[j] < nums[i]:
dp[i] = max(dp[i], dp[j] + 1)
return max(dp)
时间复杂度:O(n^2)
我们还可以使用贪心算法和二分查找来解决这个问题。
我们维护一个数组 d
,其中 d[i]
表示长度为 i 的最长递增子序列的结尾最小值,即长度为 i 的递增子序列的结尾要尽量小。
例如,在输入数组 [0, 8, 4, 12, 2] 中,当 i = 1 时,d[1] 的值应该是 8,因为长度为 1 的最长递增子序列为 [0] 或 [8],其中结尾最小的是 8。
接着,我们遍历输入数组,对于每个元素,我们在数组 d
中查找第一个比它大的元素,将其替换为当前元素。如果没有比它大的元素,我们就在数组 d
的末尾添加这个元素。
最终,数组 d
的长度就是最长递增子序列的长度。
代码如下:
def lengthOfLIS(nums):
if not nums:
return 0
d = []
for num in nums:
if not d or num > d[-1]:
d.append(num)
else:
left, right = 0, len(d) - 1
while left < right:
mid = (left + right) // 2
if d[mid] < num:
left = mid + 1
else:
right = mid
d[left] = num
return len(d)
时间复杂度:O(nlogn)
本文介绍了两种解决最长递增子序列问题的算法:动态规划和贪心算法 + 二分查找。
动态规划算法的时间复杂度是 O(n^2),空间复杂度是 O(n)。
贪心算法 + 二分查找的时间复杂度是 O(nlogn),空间复杂度是 O(n)。
在实际应用中,通常会使用贪心算法 + 二分查找来解决这个问题,因为它更加高效。