动态规划之-如何从一般到特殊解题

82 阅读2分钟

一般常规 动态规划,一般都可以往 背包问题考虑,有明确的递推公式,但是对于很多问题,直接想,很难,所以得遵循数学的归纳法,由一般到特殊来求解。

数学归纳法

  1. 当证明 N =1 时结论,成立,并且 从0-N-1 的结论均成立,那么结合已知的信息,如何能推出 N 那么此结论成立

我们的定义是这样的:dp[i] 表示以 nums[i] 这个数结尾的最长递增子序列的长度

300. 最长递增子序列

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列

image.png

已经知道了 dp[0..4] 的所有结果,我们如何通过这些已知结果推出 dp[5] 呢 nums[0] 和 nums[4] 都是小于 nums[5] 的,然后对比 dp[0] 和 dp[4] 的值,我们让 nums[5] 和更长的递增子序列结合,得出 dp[5] = 3

也就是说,实际上是 Math.max(1+1,2+1)

/**
 * @param {number[]} nums
 * @return {number}
 */
var lengthOfLIS = function(nums) {
  let dp = new Array(nums.length +1).fill(1)
  let max = 1
  
  for(let i = 1;i<nums.length;i++){
    for(let j = 0 ;j<i;j++){
      if(nums[i] > nums[j]){
        dp[i] =  Math.max(dp[i],dp[j]  + 1)
      }
      max = Math.max(max,dp[i])

    }
  }
  return max

};

674. 最长连续递增序列

给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。

连续递增的子序列 可以由两个下标 l 和 rl < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。

思路

  1. 其实这个题目的和上提区别,在于连续,既然是连续,那就之关注相邻项是否为递增,又由于,结果项总只跟前一项有关,因此不需要双重循环,也就是不需要没次都 查询 0-i-1 之间的数值,只和 i-1 项有关
/**
 * @param {number[]} nums
 * @return {number}
 */
var findLengthOfLCIS = function(nums) {
  let dp = new Array(nums.length).fill(1);
  let max = 1
  for(let i = 1;i<nums.length;i++){
    if(nums[i] > nums[i-1]){
      dp[i] = dp[i-1] +1
    }
    max = Math.max(max,dp[i])
  }
  return max
};