// 递归是一种解决问题的方法,它解决问题的各个小部分,直到解决最初的大问题。递归通常涉及函数调用自身 // 斐波那契数列尾调用优化 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))