给你一个整数数组 nums
,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7]
是数组 [0,3,1,6,2,2,7]
的子序列。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18] 输出:4 解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3] 输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7] 输出:1
提示:
1 <= nums.length <= 2500
-10^4 <= nums[i] <= 10^4
进阶:
O(n log(n))
吗?300.最长递增子序列
(1)解题思路
# 分析:当前状态受前一状态影响,且遵守类似规则的求解问题,动态规划问题
因为该子序列不一定是连续的,但需判断其与当前元素的关系,所以使用两层循环
因为只是判断相等关系,可能存在多次相同匹配,在过程中用result记录区间最大值
# 数组:截至到 i 的最长严格递增子序列的长度 dp[i]
# 递推关系:因为存在一个累计过程,如果满足当前元素递增 dp[i] = max(dp[i], dp[j]+1)
# 初始化:每个元素位置的初始递增长度都是 1
(2)过程想法
有框架之后,代码很好写
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
# 分析:当前状态受前一状态影响,且遵守类似规则的求解问题,动态规划问题
# 数组:截至到 i 的最长严格递增子序列的长度 dp[i]
# 递推关系:如果满足当前元素递增 dp[i] = max(dp[i], dp[i-1]+1)
# 初始化:每个元素位置的初始递增长度都是 1
length = len(nums)
dp = [1] * length
result = 1
for i in range(1, length): # 遍历当前节点的判断
for j in range(0, i): # 遍历当前节点之前的所有结点
if nums[i] > nums[j]:
dp[i] = max(dp[i], dp[j]+1)
result = max(result, dp[i])
return result
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
连续递增的子序列 可以由两个下标 l
和 r
(l < r
)确定,如果对于每个 l <= i < r
,都 有 nums[i] < nums[i + 1]
,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]]
就是连续递增子序列。
示例 1:
输入:nums = [1,3,5,4,7] 输出:3 解释:最长连续递增序列是 [1,3,5], 长度为3。 尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。
示例 2:
输入:nums = [2,2,2,2,2] 输出:1 解释:最长连续递增序列是 [2], 长度为1。
提示:
1 <= nums.length <= 10^4
-10^9 <= nums[i] <= 10^9
674.最长连续递增序列
(1)解题思路
# 分析:当前状态受前一状态影响,且遵守类似规则的求解问题,动态规划问题
因为该子序列是连续的,用一层循环处理即可
因为只是判断相等关系,可能存在多次相同匹配,在过程中用result记录区间最大值
# 数组:截至到 i 的最长严格递增子序列的长度 dp[i]
# 递推关系:如果满足当前元素递增 dp[i] = dp[j]+1
# 初始化:每个元素位置的初始递增长度都是 1
(2)过程想法
思路很好想,代码也很好写
class Solution:
def findLengthOfLCIS(self, nums: List[int]) -> int:
# 分析:当前状态受前一状态影响,且遵守类似规则的求解问题,动态规划问题
# 截至到 i 的最长连续递增子序列的长度 cur
# 递推关系:如果满足当前元素递增 cur = cur+1
# 初始化:每个元素位置的初始递增长度都是 1
length = len(nums)
# 利用其迭代过程,节省存储空间
cur = 1
result = 1
for i in range(1, length):
if nums[i] > nums[i-1]:
cur = cur+1
result = max(result, cur)
else:
cur = 1
return result
给两个整数数组 nums1
和 nums2
,返回 两个数组中 公共的 、长度最长的子数组的长度 。
示例 1:
输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7] 输出:3 解释:长度最长的公共子数组是 [3,2,1] 。
示例 2:
输入:nums1 = [0,0,0,0,0], nums2 = [0,0,0,0,0] 输出:5
提示:
1 <= nums1.length, nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 100
718.最长重复子数组
(1)解题思路
# 分析:存在需比较的两个数组,如果使用暴力法,其实是需要三层for循环的,根据数据的量级,是会提示超时的;当前状态受前一状态影响,且遵守类似规则的求解问题,动态规划问题。但需标记两个数组的结束指针,所以考虑使用二维DP数组。
因为只是判断相等关系,可能存在多次相同匹配,在过程中用result记录区间最大值
# 数组:nums1 截至到 i , nums2 截至到 j 的最长重复子序列的长度 dp[i][j]
# 递推关系:如果当前元素满足要求 dp[i][j] = dp[i-1][j-1]+1
# 初始化:每个元素位置的初始递增长度都是 0,但因为使用的判断条件是 nums1[i-1] 和 nums2[j-1],所以需先初始化第一行与第一列。
注:也可以使用一维滚动数组的思想,思路是类同的。
(2)过程想法
需要想到使用二维数组,后续的代码是好写的。
class Solution:
def findLength(self, nums1: List[int], nums2: List[int]) -> int:
# 分析:当前状态受前一状态影响,且遵守类似规则的求解问题,动态规划问题
# nums1 截至到 i , nums2 截至到 j 的最长重复子序列的长度 dp[i][j]
# 递推关系:如果当前元素满足要求 dp[i][j] = dp[i-1][j-1]+1
# 初始化:每个元素位置的初始递增长度都是 0
dp = [[0] * (len(nums2)+1) for _ in range(len(nums1)+1)]
# 对第一行和第一列进行初始化
for i in range(len(nums1)):
if nums1[i] == nums2[0]:
dp[i + 1][1] = 1
for j in range(len(nums2)):
if nums1[0] == nums2[j]:
dp[1][j + 1] = 1
result = 0
# 此处用的是 i-1 与 j-1 相比较,其实用 i 和 j 比较也可以,但是因为下标的原因,前者更简单
for i in range(1, len(nums1)+1):
for j in range(1, len(nums2)+1):
if nums1[i-1] == nums2[j-1]:
dp[i][j] = dp[i-1][j-1]+1
result = max(result, dp[i][j])
return result
class Solution:
def findLength(self, nums1: List[int], nums2: List[int]) -> int:
# 分析:当前状态受前一状态影响,且遵守类似规则的求解问题,动态规划问题
# nums1 截至到 i , nums2 截至到 j 的最长重复子序列的长度 dp[i][j]
# 递推关系:如果当前元素满足要求 dp[i][j] = dp[i-1][j-1]+1
# 初始化:为减少空间复杂度,采用一维滚动数组的思想存储过程变量。
# 每个元素位置的初始递增长度都是 0
dp = [0] * (len(nums2) + 1)
result = 0
# 此处用的是 i-1 与 j-1 相比较,其实用 i 和 j 比较也可以,但是因为下标的原因,前者更简单
for i in range(1, len(nums1) + 1):
pre = 0
for j in range(1, len(nums2) + 1):
cur = dp[j]
if nums1[i - 1] == nums2[j - 1]: # 如果找到相应的元素,则更迭dp数组
dp[j] = pre + 1
result = max(dp[j], result)
else: # 否则,结束更迭,重置dp数组
dp[j] = 0
pre = cur
return result