斐波那契數列和階乘的尾函式優化,動態規劃解決最小硬幣找零和揹包問題
阿新 • • 發佈:2018-12-28
// 遞迴是一種解決問題的方法,它解決問題的各個小部分,直到解決最初的大問題。遞迴通常涉及函式呼叫自身 // 斐波那契數列尾呼叫優化 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))