算法:合并石头的最低成本
题目
有 n 堆石头排成一排,第 i 堆中有 stones[i] 块石头。
每次 移动 需要将 连续的 k 堆石头合并为一堆,而这次移动的成本为这 k 堆中石头的总数。
返回把所有石头合并成一堆的最低成本。如果无法合并成一堆,返回 -1 。
示例 1:
输入:stones = [3,2,4,1], K = 2 输出:20 解释: 从 [3, 2, 4, 1] 开始。 合并 [3, 2],成本为 5,剩下 [5, 4, 1]。 合并 [4, 1],成本为 5,剩下 [5, 5]。 合并 [5, 5],成本为 10,剩下 [10]。 总成本 20,这是可能的最小值。
题解
class Solution {private int[][] memo;private int[] s;private int k;public int mergeStones(int[] stones, int k) {int n = stones.length;// (石头数量-1)/(k-1) !=0 说明无法合并成一堆//合并过程:先取k个石头合并一堆,在取k-1个继续合成一堆,依此类推if ((n - 1) % (k - 1) > 0)return -1;s = new int[n + 1];// 前缀和for (int i = 0; i < n; i++)s[i + 1] = s[i] + stones[i];this.k = k;memo = new int[n][n];for (int i = 0; i < n; ++i)// -1 表示还没有计算过Arrays.fill(memo[i], -1); return dfs(0, n - 1);}private int dfs(int i, int j) {if (i == j) return 0; // 只有一堆石头,无需合并if (memo[i][j] != -1) return memo[i][j];int res = Integer.MAX_VALUE;//子问题:起始位置不跟后面的合并,留待后面在合并//起始位置和后面的k-1合并成一堆后,留待后面在合并//起始位置和后面的k-1合并成一堆后,继续跟后面的k-1个合并成一堆,然后留待后面在合并,依此类推for (int m = i; m < j; m += k - 1)res = Math.min(res, dfs(i, m) + dfs(m + 1, j));// 可以合并成一堆,计算合并成一堆的成本if ((j - i) % (k - 1) == 0)res += s[j + 1] - s[i];return memo[i][j] = res;}
}
