问题一:最长严格递增子序列的长度
题目:
给定一个整数数组 nums ,找到其中最长严格递增子序列的长度。
状态定义:
dp[i] 表示以 nums[i] 结尾的最长严格递增子序列的长度。
状态转移方程
对于每个 nums[i],遍历其之前的所有元素 nums[j](j 从 0 到 i-1),如果 nums[i] > nums[j],则可以考虑将 nums[i] 加入到以 nums[j] 结尾的最长递增子序列中,状态转移方程为: dp[i] = max(dp[i], dp[j] + 1)。
动态规划解法:
我们使用 dp[i]
表示以 nums[i]
结尾的最长严格递增子序列的长度,不一定是连续的。(这就涉及到了选择的问题,我们需要考虑每个元素是否应该包含在递增子序列中。为了解决这个问题,我们使用动态规划数组 dp,其中 dp[i] 表示以 nums[i] 结尾的最长递增子序列的长度。在更新 dp[i] 的过程中,需要考虑所有比 nums[i] 小的元素,并选择其中最长的递增子序列进行延伸。这就需要使用两层循环,其中外层循环遍历每个元素,内层循环遍历之前的元素,以确保每个元素都被考虑。)为了求解 dp[i]
,我们需要考虑所有在 i
之前的元素 nums[j]
,其中 j
可以从 0
到 i-1
。如果 nums[i] > nums[j]
,说明 nums[i]
可以接在以 nums[j]
结尾的递增子序列后面,此时 dp[i] = dp[j] + 1
。
def lengthOfLIS(nums):
if not nums:
return 0
n = len(nums)
dp = [1] * n
for i in range(n):
for j in range(i):
if nums[i] > nums[j]:
dp[i] = max(dp[i], dp[j] + 1)
return max(dp)
问题二:最长连续递增子序列的长度
题目:
给定一个未经排序的整数数组,找到最长且连续递增的子序列,并返回该序列的长度。
状态定义:
dp[i] 表示以 nums[i] 结尾的最长连续递增子序列的长度。
状态转移方程:
如果 nums[i] > nums[i-1],则 dp[i] = dp[i-1] + 1;否则,重新开始计算连续递增子序列,dp[i] = 1。
动态规划解法:
我们使用 dp[i]
表示以 nums[i]
结尾的最长连续递增子序列的长度。在这个问题中,我们只需要考虑当前元素和前一个元素的关系,如果 nums[i] > nums[i-1]
,说明可以将 nums[i]
加入到连续递增子序列中,此时 dp[i] = dp[i-1] + 1
;否则,重新开始计算连续递增子序列,dp[i] = 1
。
def findLengthOfLCIS(nums):
if not nums:
return 0
n = len(nums)
dp = [1] * n
for i in range(1, n):
if nums[i] > nums[i - 1]:
dp[i] = dp[i - 1] + 1
else:
dp[i] = 1
return max(dp)
总结:
在动态规划中,问题的性质决定了状态转移的方式。在第一个问题中,子问题的解之间存在较为复杂的依赖关系,因此需要通过两层循环来更新动态规划数组。而在第二个问题中,子问题的解之间的依赖相对简单,只与前一个状态相关,因此只需要一层循环即可。
在第一个问题中,我们需要考虑每个元素与之前所有元素的关系,因此使用两层循环。而在第二个问题中,我们只需要考虑当前元素和前一个元素的关系,因此只需要一层循环。这反映了问题性质和解决方法的差异。