300.最长递增子序列给你一个整数数组 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] 104dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度if (nums[i] nums[j]) dp[i] max(dp[i], dp[j] 1);每一个i对应的dp[i]即最长递增子序列起始大小至少都是1.dp[i] 是有0到i-1各个位置的最长递增子序列 推导而来那么遍历i一定是从前向后遍历。j其实就是遍历0到i-1那么是从前到后还是从后到前遍历都无所谓只要吧 0 到 i-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 result674. 最长连续递增序列给定一个未经排序的整数数组找到最长且 连续递增的子序列并返回该序列的长度。连续递增的子序列 可以由两个下标 l 和 rl 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。提示0 nums.length 10^4-10^9 nums[i] 10^9dp[i]以下标i为结尾的连续递增的子序列长度为dp[i]。如果 nums[i] nums[i - 1]那么以 i 为结尾的连续递增的子序列长度 一定等于 以i - 1为结尾的连续递增的子序列长度 1 。即dp[i] dp[i - 1] 1;以下标i为结尾的连续递增的子序列长度最少也应该是1即就是nums[i]这一个元素。所以dp[i]应该初始1;class Solution: def findLengthOfLCIS(self, nums: List[int]) - int: if len(nums) 0: return 0 result 1 dp [1] * len(nums) for i in range(len(nums)-1): if nums[i1] nums[i]: #连续记录 dp[i1] dp[i] 1 result max(result, dp[i1]) return result718. 最长重复子数组给两个整数数组 A 和 B 返回两个数组中公共的、长度最长的子数组的长度。示例输入A: [1,2,3,2,1]B: [3,2,1,4,7]输出3解释长度最长的公共子数组是 [3, 2, 1] 。提示1 len(A), len(B) 10000 A[i], B[i] 100dp[i][j] 以下标i - 1为结尾的A和以下标j - 1为结尾的B最长重复子数组长度为dp[i][j]。 特别注意 “以下标i - 1为结尾的A” 标明一定是 以A[i-1]为结尾的字符串 根据dp[i][j]的定义dp[i][j]的状态只能由dp[i - 1][j - 1]推导出来。即当A[i - 1] 和B[j - 1]相等的时候dp[i][j] dp[i - 1][j - 1] 1;根据递推公式可以看出遍历i 和 j 要从1开始2维DPclass Solution: def findLength(self, nums1: List[int], nums2: List[int]) - int: # 创建一个二维数组 dp用于存储最长公共子数组的长度 dp [[0] * (len(nums2) 1) for _ in range(len(nums1) 1)] # 记录最长公共子数组的长度 result 0 # 遍历数组 nums1 for i in range(1, len(nums1) 1): # 遍历数组 nums2 for j in range(1, len(nums2) 1): # 如果 nums1[i-1] 和 nums2[j-1] 相等 if nums1[i - 1] nums2[j - 1]: # 在当前位置上的最长公共子数组长度为前一个位置上的长度加一 dp[i][j] dp[i - 1][j - 1] 1 # 更新最长公共子数组的长度 if dp[i][j] result: result dp[i][j] # 返回最长公共子数组的长度 return result1维DPclass Solution: def findLength(self, nums1: List[int], nums2: List[int]) - int: # 创建一个一维数组 dp用于存储最长公共子数组的长度 dp [0] * (len(nums2) 1) # 记录最长公共子数组的长度 result 0 # 遍历数组 nums1 for i in range(1, len(nums1) 1): # 用于保存上一个位置的值 prev 0 # 遍历数组 nums2 for j in range(1, len(nums2) 1): # 保存当前位置的值因为会在后面被更新 current dp[j] # 如果 nums1[i-1] 和 nums2[j-1] 相等 if nums1[i - 1] nums2[j - 1]: # 在当前位置上的最长公共子数组长度为上一个位置的长度加一 dp[j] prev 1 # 更新最长公共子数组的长度 if dp[j] result: result dp[j] else: # 如果不相等将当前位置的值置为零 dp[j] 0 # 更新 prev 变量为当前位置的值供下一次迭代使用 prev current # 返回最长公共子数组的长度 return result
算法训练营Day41 - 动态规划part10
300.最长递增子序列给你一个整数数组 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] 104dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度if (nums[i] nums[j]) dp[i] max(dp[i], dp[j] 1);每一个i对应的dp[i]即最长递增子序列起始大小至少都是1.dp[i] 是有0到i-1各个位置的最长递增子序列 推导而来那么遍历i一定是从前向后遍历。j其实就是遍历0到i-1那么是从前到后还是从后到前遍历都无所谓只要吧 0 到 i-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 result674. 最长连续递增序列给定一个未经排序的整数数组找到最长且 连续递增的子序列并返回该序列的长度。连续递增的子序列 可以由两个下标 l 和 rl 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。提示0 nums.length 10^4-10^9 nums[i] 10^9dp[i]以下标i为结尾的连续递增的子序列长度为dp[i]。如果 nums[i] nums[i - 1]那么以 i 为结尾的连续递增的子序列长度 一定等于 以i - 1为结尾的连续递增的子序列长度 1 。即dp[i] dp[i - 1] 1;以下标i为结尾的连续递增的子序列长度最少也应该是1即就是nums[i]这一个元素。所以dp[i]应该初始1;class Solution: def findLengthOfLCIS(self, nums: List[int]) - int: if len(nums) 0: return 0 result 1 dp [1] * len(nums) for i in range(len(nums)-1): if nums[i1] nums[i]: #连续记录 dp[i1] dp[i] 1 result max(result, dp[i1]) return result718. 最长重复子数组给两个整数数组 A 和 B 返回两个数组中公共的、长度最长的子数组的长度。示例输入A: [1,2,3,2,1]B: [3,2,1,4,7]输出3解释长度最长的公共子数组是 [3, 2, 1] 。提示1 len(A), len(B) 10000 A[i], B[i] 100dp[i][j] 以下标i - 1为结尾的A和以下标j - 1为结尾的B最长重复子数组长度为dp[i][j]。 特别注意 “以下标i - 1为结尾的A” 标明一定是 以A[i-1]为结尾的字符串 根据dp[i][j]的定义dp[i][j]的状态只能由dp[i - 1][j - 1]推导出来。即当A[i - 1] 和B[j - 1]相等的时候dp[i][j] dp[i - 1][j - 1] 1;根据递推公式可以看出遍历i 和 j 要从1开始2维DPclass Solution: def findLength(self, nums1: List[int], nums2: List[int]) - int: # 创建一个二维数组 dp用于存储最长公共子数组的长度 dp [[0] * (len(nums2) 1) for _ in range(len(nums1) 1)] # 记录最长公共子数组的长度 result 0 # 遍历数组 nums1 for i in range(1, len(nums1) 1): # 遍历数组 nums2 for j in range(1, len(nums2) 1): # 如果 nums1[i-1] 和 nums2[j-1] 相等 if nums1[i - 1] nums2[j - 1]: # 在当前位置上的最长公共子数组长度为前一个位置上的长度加一 dp[i][j] dp[i - 1][j - 1] 1 # 更新最长公共子数组的长度 if dp[i][j] result: result dp[i][j] # 返回最长公共子数组的长度 return result1维DPclass Solution: def findLength(self, nums1: List[int], nums2: List[int]) - int: # 创建一个一维数组 dp用于存储最长公共子数组的长度 dp [0] * (len(nums2) 1) # 记录最长公共子数组的长度 result 0 # 遍历数组 nums1 for i in range(1, len(nums1) 1): # 用于保存上一个位置的值 prev 0 # 遍历数组 nums2 for j in range(1, len(nums2) 1): # 保存当前位置的值因为会在后面被更新 current dp[j] # 如果 nums1[i-1] 和 nums2[j-1] 相等 if nums1[i - 1] nums2[j - 1]: # 在当前位置上的最长公共子数组长度为上一个位置的长度加一 dp[j] prev 1 # 更新最长公共子数组的长度 if dp[j] result: result dp[j] else: # 如果不相等将当前位置的值置为零 dp[j] 0 # 更新 prev 变量为当前位置的值供下一次迭代使用 prev current # 返回最长公共子数组的长度 return result