题目:给定一个无序的整数数组,找到其中最长上升子序列的长度。
给定一个未经排序的整数数组,找到最长且连续的的递增序列。
输入: [1,3,5,4,7]
输出: 3
解释: 最长连续递增序列是 [1,3,5], 长度为3。
尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为5和7在原数组里被4隔开。
理解:重点把握连续,动态规划.
初始化:dp=[1]*n
转移矩阵为if nums[i]>nums[j]->dp[i]=dp[j]+1。
输出:max(dp)
class Solution:
def findLengthOfLCIS(self, nums: List[int]) -> int:
n = len(nums)
if n<=1:
return n
dp = [1]*n
for i in range(1,n):
if nums[i]>nums[i-1]:
dp[i] = dp[i-1]+1
return max(dp)
进阶1:给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
理解:由于题目只要最长上升子序列得长度,并不要求实际子序列。因此可直接利用动态规划。与题一要求不同的是:这个是子序列,而不要求连续。因此需要加一层循环,遍历0-i之间的所有状态。
初始状态为:dp[i] =1。dp[i]代表的是位置i得到的最长上升子序列的长度,因此初始化为1表示只有一个i字符满足条件得情况下则最长上升子串长度即为1。
转移矩阵:dp[i] = max(dp[i], dp[j]+1)。j属于(0,i)。相当于两层遍历,针对0-i之间的位置j, 如果i>j, 则可更新dp[i]=dp[j]+1,当然要针对0-i之间所有的选取最大值作为位置i的状态。.
输出:dp所有位置的最大值即可。
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
n = len(nums)
if n==0:
return 0
dp =[]
for i in range(n):
dp.append(1)
for j in range(i):
if nums[i]>nums[j]:
dp[i] = max(dp[i], dp[j]+1)
return max(dp)
当然还有二分+贪心的算法。核心思想为:每次都选取离最大值最近的值进行递增。
进阶2求最长递增子序列的个数。
输入: [1,3,5,4,7]
输出: 2
解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。
输入: [2,2,2,2,2]
输出: 5
解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5。
理解:相当于求递增子序列的基础之上统计个数,因此直观理解,需要在长度的dp之上增加一个count数组统计当前位置最长子序列的个数,表示当前最长上升子序列可以得到的个数。
初始化:当然都为1
状态转移矩阵:在满足nums[i]>nums[j],即可以递增的情况下进行分类。1)如果dp[i]<=dp[j],即还没有基于状态j进行最长递增子序列的更新:此时更新最长递增子序列dp[i]=dp[j]=1,并且count[i]应等于count[j]。2)如果dp[i]==dp[j]+1,表明此时已经基于j进行子序列更新或者等同长度的更新,如12435中,更新5时,由3的状态得到dp[i]=4,而由4的状态也可以得到dp[i]=4,因此,需要将count[3]+count[4]:那么count[i]+=count[j]。
def findNumberOfLIS(self, nums: List[int]) -> int:
n = len(nums)
if n==0:
return 0
dp =[]
count = [1]*n #存储当前i结尾的最长子串的个数
for i in range(n):
dp.append(1)
for j in range(i):
if nums[i]>nums[j]:#可以上升
#dp[i] = max(dp[i], dp[j]+1)
#新增判断
if dp[i] <= dp[j]:#还未上升过
dp[i] = dp[j] +1
count[i] = count[j]#由j上升的得到的i,自己个数等同于j的个数
elif dp[i] == dp[j]+1:#如12435中,5可以由3得到,也可以由4得到。
count[i] += count[j]
max_length = max(dp)
return sum(c for i, c in enumerate(count) if dp[i] == max_length)
进阶3输出该最长上升子序列。
思路:利用回溯法,基于最长上升子序列的输出dp[i], 及其位置。然后从后往前找dp[i]-1的位置加入到res中.
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
n = len(nums)
if n==0:
return 0
dp =[]
pos = 1
for i in range(n):
dp.append(1)
for j in range(i):
if nums[i]>nums[j]:
dp[i] = max(dp[i], dp[j]+1)
pos = i#找出最大的那个位置,从后往前找
deepth = max(dp)#输出最大的值
res = []
for j in range(pos, -1, -1):
if dp[j] = deepth:
res.insert(0, nums[j])
deepth -=1#最长上升子序列的长度值依次减一往前找。
return res