数据结构与算法-动态规划

275 阅读1分钟

1、递推

递推关系式(Recurrence relation),在数学上也就是差分方程,是一种递推地定义一个序列方程:序列的每一项目是定义为前若干项的函数: 像斐波那契数即为递推关系

 Xn+2 = Xn+1 + Xn

与递归的区别

Recursion,指程序调用自身的编程技巧

斐波那契数列

var fib = function(n) {
   arr = [0 ,1]
   for(let i =2; i<= n; i++){
       arr[i] = arr[i - 1] + arr[i - 2]
       arr[i] %= (1e9+7)
   }
   return arr[n]
};

爬楼梯

var climbStairs = function(n) {
   if(n<=3){
     return n
   }
   let arr = [0,1,2,3]
   for(let i = 4; i<n; i++){
       arr[i] = arr[i-1] + arr[i-2]
   }
   return arr[n-1] + arr[n-2]
};

2、动态规划

Dynamic Programming 简称DP,是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。通常会有暴力解决以及优化解决方案,二者用时差别较大

与递推、递归

动态规划,通常离不开递推公式、递归

与数学

求值单个数值的dp题,通常会有数学公式求解法,当然这个需要较高的数学功底,这个通常在竞赛中常见,但是面试一般不做要求,面试中更多考察dp的优化版解法

动态规划解题思路

  • 大事化小
  • 小事化了
  • 优化:记忆求值 有效求值

leetcode 746 使用最小花费爬楼梯

var minCostClimbingStairs = function(cost) {
   let len = cost.length
   let dp = [0, 0]
   for(let i =2; i <=len ; i++){
       dp[i] = Math.min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
   }
   return dp[len]
};

优化以后

var minCostClimbingStairs = function(cost) {
   let len = cost.length
   let prev = 0,
    current = 0, 
    next;
   for(let i =2; i <=len; i++){
      next = Math.min(current + cost[i -1], prev + cost[i-2])
      prev = current
      current = next
   }
   return current
};

leetcode 121. 买卖股票的最佳时机

var maxProfit = function(prices) {
  let max = 0
  const len = prices.length;
  for(let i=0; i<len - 1; i++){
      for(let j = i+ 1; j<len; j++){
          max = Math.max(max, prices[j] - prices[i])
      }
  }
  return max
};

优化后

var maxProfit = function(prices) {
  let max = 0
  const len = prices.length;
  let minPrice = prices[0]
  for(let i=0; i<len; i++){
     if(prices[i]<minPrice){
       minPrice = prices[i]
     }else{
       max = Math.max(max, prices[i] - minPrice)
     }
  }
  return max
};

剑指 Offer II 095. 最长公共子序列

var longestCommonSubsequence = function(text1, text2) {
   const m = text1.length;
   const n = text2.length;
   const dp = [new Array(n + 1).fill(0)];
   for(let i = 1;i <= m; i++){
        const c1 = text1[i-1];
        dp[i] = [0];
       for(let j=1; j<=n; j++){
        const c2 = text2[j-1];
        if(c1 ===c2){
            dp[i][j] = dp[i-1][j-1] + 1;
        }else{
            dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
        }
       }
   }
   return dp[m][n];
};

leetcode 300. 最长递增子序列

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

优化后