動態規劃練習題彙總segmentfault
描述
有N堆石子排成一排,每堆石子有必定的數量。現要將N堆石子併成爲一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價爲這兩堆石子的和,通過N-1次合併後成爲一堆。求出總的代價最小值。
輸入
序列n,序列值表示第i堆石子的數量,0<=i<n,如:[4,2,3,9,6,8,1,7]
輸出
輸出總代價的最小值this
1 思路
最早合併的石子堆在後期中可能被屢次合併,所以最早合併的石子堆數量越小越好code
2 拆分子問題
每次進行合併,須要從當前的石子堆中選取兩個相鄰的石子數量和最少的做爲被合併的堆get
3 計算
令第i次合併後的總代價爲C(i),C(0)=0,則C(i+1)=C(i)+min{序列[k]+序列[k+1]},其中 0<=i<n-1,0<=k<n-1-iio
4 代碼
bottom-up DPconsole
const stoneArray = [4, 2, 3, 9, 6, 8, 1, 7]; class CalStone { constructor(options) { this.stoneArray = Array.isArray(options) ? options : []; } getStoreBottomUp() { let i = 0; const len = this.stoneArray.length; while (++i < len) { let min = { sum: 99999999999, index: [-1, -1] }; for (let i = 0; i < this.stoneArray.length - 1;i++){ const sum = this.stoneArray[i] + this.stoneArray[i + 1]; min = sum < min.sum ? { sum: sum, index: [i, i + 1] } : min; } this.stoneArray = [].concat(this.stoneArray.slice(0, min.index[0]), min.sum, this.stoneArray.slice(min.index[1]+1)); } console.log(`總代價爲 ${this.stoneArray[0]}`); } } new CalStone(stoneArray).getStoreBottomUp();
recursive DPclass
const stoneArray = [4, 2, 3, 9, 6, 8, 1, 7]; class CalStone { constructor(options) { this.stoneArray = Array.isArray(options) ? options : []; } getStoneRecursive(arr = this.stoneArray) { if (arr.length === 1) { console.log(`總代價爲 ${arr[0]}`); return arr; } else { let min = { sum: 99999999999, index: [-1, -1] }; for (let i = 0; i < arr.length - 1; i++) { const sum = arr[i] + arr[i + 1]; min = sum < min.sum ? { sum: sum, index: [i, i + 1] } : min; } const newStoneArr = [].concat(arr.slice(0, min.index[0]), min.sum, arr.slice(min.index[1] + 1)); return this.getStoneRecursive(newStoneArr); } } } new CalStone(stoneArray).getStoneRecursive();
5 時間複雜度
須要進行n-1次合併,第i次合併須要進行n-i次比較,故時間複雜度爲O(n2)動態規劃