斐波那契数列和阶乘的尾函数优化,动态规划解决最小硬币找零和揹包问题

 // 递归是一种解决问题的方法,它解决问题的各个小部分,直到解决最初的大问题。递归通常涉及函数调用自身 // 斐波那契数列尾调用优化  function fibonacci(n, acc1 = 1, acc2 = 1) {
   if (n === 1 || n === 2) {
     return acc1
   }
   return fib(n - 1, acc1 + acc2, acc1)
 }
// 非递归方式实现  function fib(n) {
   let acc1 = 1, acc2 = 1
   while (n > 2) {
     [acc1, acc2] = [acc2, acc1 + acc2]
     n --
   }
   return acc2
 }
 //console.log(fib(6))  // 尾递归阶乘  function factorial(n, p = 1) {
  if (n === 1) {
    return 1 * p
  }
   return factorial(n -1, n * p)
 }
 // console.log(factorial(4))     // 动态规划是一种将复杂问题分解成更小的子问题来解决的优化计数  //动态规划和分而治之(归并排序和快速排序算法中用到的)是不同的方案,分而治之方法是把问题分解成相互独立的子问题,然后组合它们的答案, // 而动态规划则是将问题分解成相互依赖的子问题   //最小硬币找零问题   class MinCoinChange {
  constructor (coins) {
    this.coins = coins
    this.cache = []
  }
  makeChange (amount) {
    if (!amount) {
      return []
    }
    if (this.cache[amount]) {
      return this.cache[amount]
    }
    let min = [], newAmount, newMin, i, len = this.coins.length, coin
    for (i = len; i--;) {
      coin = this.coins[i]
      newAmount = amount - coin
      if (newAmount >= 0) { // 剩余金额大于等于0,当前找零币才有效  newMin = this.makeChange(newAmount) // 递归获取找零币的数组  if ((newMin < min.length - 1 || !min.length) && (newMin.length || !newAmount)) {
          // newMin < min.length - 1 || !min.length 新的数组必须小于当前的最小数组或者当前的最小数组为空才更新, 减一是因为newMin还有一个coin币没有加入  // newMin.length || !newAmount 只有当newMin存在或者有剩余金额(存在coin)才更新  min = [coin].concat(newMin)
        }
      }
    }
    return this.cache[amount] = min
  }
 }
 let minCoinChange = new MinCoinChange([1, 5, 10, 25])
 // console.log(minCoinChange.makeChange(36))   // 揹包问题  // 揹包问题是一个组合优化问题,它可以描述如下,给定一个固定大小,能够携重W的揹包,以及一组有价值和重量的物品,  // 找出一个最佳解决方案,使得装入揹包的物品总重量不超过W,且价值最大   // 物品 重量 价值  // 1 2 3  // 2 3 4  // 3 4 5  // capacity 固定重量 weights 重量数组 values 价值数组  function knapSack(capacity, weights, values) {
   let i, w, ks = [], n = values.length, a, b
   for (i = n + 1; i--;) { // 初始化矩阵  ks [i] = []
   }
   for (i = 0; i <= n; i++) {
     for (w = 0; w <= capacity ; w++) {
       if (i === 0 || w === 0) {
         ks[i][w] = 0
       } else if (weights[i - 1] <= w) { // 如果当前价值对应的重量小于固定重量  a = values[i - 1] + ks[i - 1][w - weights[i - 1]]  // 当前价值 + (固定重量 - 前价值对应的重量)剩余价值  b = ks[i - 1][w] // 上一个物品的价值  ks[i][w] = a > b ? a : b
       } else {
         ks[i][w] = ks[i - 1][w]
       }
     }
   }
   return ks[n][capacity]
 }


let values = [3, 4, 5],
  weights = [2, 3, 4],
  capacity = 5
 console.log(knapSack(capacity, weights, values))
点赞