继续补卡,300. 最长递增子序列,674. 最长连续递增序列,718. 最长重复子数组,今天开始子序列部分,感觉DP还是那种感觉,能想出来数组对应的是什么,即把dp[i][j]这个想明白就好做,但是大多数时候想不明白,甚至都看不出来怎么使用递归。
300. 最长递增子序列
感觉进入一个新的DP系列问题,最主要的就是了解dp[i]的意义,因为一个系列中的下标含义都比较接近,子序列中多为这种定义:dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度。初始化是全为1的一维数组,1代表了本身就是本身长度为1。然后进行双层的遍历,其中i是从第二到尾,j是从0到i。简单说就是i控制了遍历的长度,j去分别对长度内进行比较,算最大长度。
然后就是题目里比较难理解的递推公式,也就是当数字i大于数字j的时候,就进行dp[i] = max(dp[i],dp[j]+1)的操作。其实就是从i=1开始一层一层遍历,求出每一层的每一个dp[i]的最大长度,比如第一层就是[0,1]这个数组,然后它的最大长度是2,在dp[1]这个位置。以i=3为例,j的遍历范围就是0到3。此时dp[3]=1,nums[3]=3,然后j从下标0开始遍历,发现nums[3]>nums[1],然后就执行max(dp[3],dp[0]+1)得到2,之后同样的在下标1的时候得到3,到下标2的时候得到2,这就是为什么取max而不是直接用dp[j]+1替换dp[i]的原因,就是来避免出现小,大,次大,更大这种情况,这种情况本应该是3,如果直接替换就会出现长度4。
然后是连续递增子序列就比较简单,也不需要j来从头遍历防止刚说的这种情况,直接用dp[i-1]+1这种方式进行状态转移就行了,如果不符合递增这种情况,就是会自动会到初始的长度1开始重新遍历。

class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
if len(nums) <= 1:
return len(nums)
dp = [1] * len(nums)
result = 1
for i in range(1,len(nums)):
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
#连续递增子序列
class Solution:
def findLengthOfLCIS(self, nums: List[int]) -> int:
if len(nums) <= 1:
return len(nums)
dp = [1] * len(nums)
result = 1
for i in range(1,len(nums)):
if nums[i] > nums[i-1]:
dp[i] = dp[i-1] +1
result = max(result, dp[i])
return result
718. 最长重复子数组
又是没太多思路的一道题,想到应该用二维数组,并且一边是数组A一边是数组B但是后续做的时候还是出很多问题,最大的问题就是边界,感觉这道题虽然理解上不算很难但是需要注意的点还是挺多的。
第一个,dp[i][j]的定义dp[i][j] :以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]。 (特别注意: “以下标i - 1为结尾的A” 标明一定是 以A[i-1]为结尾的字符串 )。这个定义确实很难想出来,这也是解决边界问题最重要的一点,也是解决了初始化难题。即在二维数组中,多添加一行和一列0,可以看出在创建数组的时候就是类似[0]*n+1这种。这样做的好处就是方便初始化,因为你直接开始,可以看出在第一行和第一列中,有时候数组开头就是相等的,这时候初始化就不是0而是1了,比如第二行第四列的1,这种情况的初始化需要多个二次遍历去初始。
第二个点,递推公式,dp[i][j] = dp[i - 1][j - 1] + 1,为什么状态转移是从[i-1][j-1]而不是类似[i-1][j]这种的,因为这样比较的是A中以i-2结尾的子数组 和 B中以j-1结尾的子数组最长公共子数组长度,因此是断开的,不是连续子数组了。换句话说,i和j同时看后面一个数的大小,不能只看一边。另外比较的是if nums1[i - 1] == nums2[j - 1],是为了不遗漏,因为遍历是从1开始的,更改的dp[i][j]。
第一次做这种题,确实没想到二维数组还能用多增添一行一列这种方式来进行简化,但是看图的话会容易理解不少。

class Solution:
def findLength(self, nums1: List[int], nums2: List[int]) -> int:
n1,n2 = len(nums1),len(nums2)
dp = [[0] * (n2+1) for _ in range(n1+1)]
result = 0
for i in range(1, n1+1):
for j in range(1, n2+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
755

被折叠的 条评论
为什么被折叠?



