题目:最长上升子序列
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18],输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
-------------------------------------------------------------------------------
思路:典型的动态规划问题,设立1个dp list,用于保存当前元素nums[i]跟前面比它小的元素构成的最长序列。
解法1#:动态规划
class Solution(object):
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if not nums:
return 0
if len(nums) == 1:
return 1
max_len = 0
dp = [1 for _ in range(len(nums))]
for i in range(1, len(nums)):
for j in range(0,i):
if nums[j] < nums[i]:
# 如果nums[j]小于nums[i], 就在dp[j]的基础上+1
dp[i] = max(dp[j]+1, dp[i])
max_len = max(dp[i], max_len)
return max_len
解法2#:动态规划+二分查找,通过二分法不断插入新元素来寻找最长序列。速度极快
class Solution(object):
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if not nums:
return 0
if len(nums) == 1:
return 1
# 用于临时存放数组序列
tmp_array = [nums[0]]
control_num = True
# 将nums[i]按顺序放到tmp_array的合适位置
for i in range(1, len(nums)):
# 如果遇到更小的元素,且tmp_array只有一个元素,直接替换掉
if nums[i] < tmp_array[0] and control_num:
tmp_array[0] = nums[i]
elif nums[i] >= tmp_array[-1]:
tmp_array.append(nums[i])
control_num = False
# 介于最小和最大之间,就用二分法插入
elif tmp_array[0] < nums[i] < tmp_array[-1]:
index = self.semiInsert(nums[i], tmp_array, 0, len(tmp_array)-1)
def semiInsert(self, num, tmp_array, first, last):
if first > last:
return -1
mid = (first+last) // 2
# 我们需要找到的是介于两个相邻值之间的位置mid
if tmp_array[mid] > num:
if num >= tmp_array[mid-1]:
return mid
else:
last = mid-1
else:
first = mid + 1
return self.semiInsert(num, tmp_array, first, last)
参考:
https://blog.csdn.net/qq_32424059/article/details/88076376
https://blog.csdn.net/wenqiwenqi123/article/details/81327682
https://blog.csdn.net/yingzoe/article/details/88987893