Given an unsorted array of integers, find the length of longest increasing subsequence.
Example:
Input: [10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.
Note:
- There may be more than one LIS combination, it is only necessary for you to return the length.
- Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
LeetCode:链接
第一种方法:动态规划(Dynamic Programming),时间复杂度O(n^2)
状态转移方程:dp[x] = max(dp[x], dp[y] + 1) 其中 y < x 并且 nums[x] > nums[y]
class Solution(object):
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
length = len(nums)
dp = [1] * length
for i in range(length):
for j in range(i):
if nums[i] > nums[j]:
dp[i] = max(dp[i], dp[j]+1)
return max(dp) if dp else 0
第二种方法:二分法,时间复杂度O(n * log n)
思路是,我们先建立一个数组 ends,把首元素放进去,然后比较之后的元素。
- 如果遍历到的新元素比ends数组中的首元素小的话,替换首元素为此新元素,
- 如果遍历到的新元素比ends数组中的末尾元素还大的话,将此新元素添加到ends数组末尾(注意不覆盖原末尾元素)。
- 如果遍历到的新元素比ends数组首元素大,比尾元素小时,此时用二分查找法找到第一个不小于此新元素的位置,覆盖掉位置的原来的数字,
以此类推直至遍历完整个 nums 数组,此时 ends 数组的长度就是我们要求的 LIS 的长度,特别注意的是 ends 数组的值可能不是一个真实的LIS,比如若输入数组nums为 {4, 2, 4, 5, 3, 7},那么算完后的ends数组为{2, 3, 5, 7},可以发现它不是一个原数组的LIS,只是长度相等而已,千万要注意这点。
class Solution(object):
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
if n == 0:
return 0
number = [nums[0]]
for i in range(1, n):
if nums[i] < number[0]:
number[0] = nums[i]
elif nums[i] > number[-1]:
number.append(nums[i])
else:
low = 0
high = len(number) - 1
while low <= high:
mid = (low + high) // 2
if nums[i] > number[mid]:
low = mid + 1
else:
high = mid - 1
number[low] = nums[i]
return len(number)