1000. 合并石头的最低成本 - 力扣(LeetCode)

一、题目

有 N 堆石头排成一排,第 i 堆中有 stones[i] 块石头。

每次移动(move)需要将连续的 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,这是可能的最小值。

示例 2:
输入:stones = [3,2,4,1], K = 3
输出:-1
解释:任何合并操作后,都会剩下 2 堆,我们无法再进行合并。所以这项任务是不可能完成的。

示例 3:
输入:stones = [3,5,1,2,6], K = 3
输出:25
解释:
从 [3, 5, 1, 2, 6] 开始。
合并 [5, 1, 2],成本为 8,剩下 [3, 8, 6]。
合并 [3, 8, 6],成本为 17,剩下 [17]。
总成本 25,这是可能的最小值。

提示:

  • 1 <= stones.length <= 30
  • 2 <= K <= 30
  • 1 <= stones[i] <= 100

二、代码

class Solution {public int mergeStones(int[] stones, int k) {// 过滤无效参数if (stones == null || stones.length == 0 || k == 0) {return -1;}// 数组长度int n = stones.length;// 这个条件很重要,存在一些数组长度n和k的组合压根就合并不成1个,直接返回-1if ((n - 1) % (k - 1) > 0) {return -1;}// 构造前缀和数组,加速求任意区间累加和的速度int[] preSum = new int[n];preSum[0] = stones[0];for (int i = 1; i < n; i++) {preSum[i] = preSum[i - 1] + stones[i];}// 构造三维dp缓存  第三维下标在递归中最多赋值就是k,所以长度开到k+1即可int[][][] dp = new int[n][n][k + 1];// 将数组0~n-1范围合并成1份,每一次将相邻的k个合并return process(stones, 0, n - 1, 1, k, preSum, dp);}// arr[l..r] 一定要弄出p份,返回最低代价// 固定参数是k和preSum,preSum是用来加快求累加和速度的public int process(int[] stones, int l, int r, int p, int k, int[] preSum, int[][][] dp) {// 先看是否有缓存,有的话直接返回if (dp[l][r][p] != 0) {return dp[l][r][p];}// basecase  如果此时l==r,说明本身就是1个数了,如果要划分的目标p也是1,那么就不需要再合并了,代价直接返回0,如果目标p不是1,但是因为此时l~r范围只有一个数了,肯定是合并不出来p目标了,直接返回-1if (l == r) {dp[l][r][p] = p == 1 ? 0 : -1;return dp[l][r][p];}// 说明当前就是最后一次合并了,合并完就要求是1个,如果无法一次合并成1个,就返回-1if (p == 1) {// 当前是最后一次合并了,如果要想是最后一次合并,此时合并完只能由k个数,所以要判断当前的状况能不能合并出k份int next = process(stones, l, r, k, k, preSum, dp);// 如果不能合并成k份,那么一定就无法最后合并成一份,直接返回-1if (next == -1) {dp[l][r][p] = -1;return dp[l][r][p];// 可以合并出三份} else {// 代价就是合并出三分所需要的总代价,加上l~r范围的累加和,因为将3份数合并,合并代价就是这三部分的累加和dp[l][r][p] = next + (l == 0 ? preSum[r] : preSum[r] - preSum[l - 1]);return dp[l][r][p];}// 当前目标并不是分成1份,说明合并还没有到最后 } else {// 先将最小代价初始化为系统最大int min = Integer.MAX_VALUE;// 开始遍历,尝试所有可能的左右部分划分情况,我们就规定左部分划分出1份,右部分划分出p-1份// 划分遍历步长就是k - 1,l最多到r - (p - 1),因为要保证右部分至少有p-1个数,不然就不可能划分出p-1个目标了for (int mid = l; mid <= r - (p - 1); mid += (k - 1)) {// 看左部分合并成1份最低代价int leftCost = process(stones, l, mid, 1, k, preSum, dp);int rightCost = -1;// 如果左部分确实可以划分出1份,就去看右部分能不能划分出p-1份。剪枝if (leftCost != -1) {// 右部分合并出p-1份的最低代价rightCost = process(stones, mid + 1, r, p - 1, k, preSum, dp);}// 如果右部分也可以划分出来,则计算这两部分的合并代价,是否是l~r范围所有划分情况中最低的if (rightCost != -1) {// 这里我们就是要将l~r范围合并出p份,并不会对这p份再做合并,所以这里的代价就是leftCost+rightCost,不需要加上l~r的累加和min = Math.min(min, leftCost + rightCost);}}// 返回所有划分中合并代价最小的值dp[l][r][p] = min;return dp[l][r][p];}}
}

三、解题思路

定义process函数:让L...R一定变为P份,返回合并成P份的最少代价是啥。

枚举最左边的一份是什么范围,这样就可以递归出左部分和右部分的最低代价。我们将每一层递归的所有可能的范围都枚举尝试一遍,最后就能求出来结果。

这里我们就认为左边搞成1份,右边搞成P-1份,因为总归是存在一种划分能让左边搞出来1份,我们把所有可能的左部分范围都尝试一遍,就能得到全部左部分和右部分的情况。而且必须要来一个左右部分,因为只有划分为1份的时候才是递归出口,所以我们就要想到让左边固定搞1份,这样才能让整个递归过程结束返回。

【LeetCode】合并石头的最低成本 [H](动态规划)相关推荐

  1. LeetCode 1000. 合并石头的最低成本(经典区间DP)

    1000. 合并石头的最低成本 定义dp[i][j]为尽可能多的合并区间[i, j] 所需的成本,不一定能合并成一堆,但合并完成后剩下的堆数一定小于k,更具体地,剩余的堆数一定是(n - 1) % ( ...

  2. 2021-08-24:合并石头的最低成本。有 N 堆石头排成一排,第 i 堆中有 stones[i] 块石头。每次移动(move)需要将连续的 K 堆石头合并为一堆,而这个移动的成本为这 K 堆石头的

    2021-08-24:合并石头的最低成本.有 N 堆石头排成一排,第 i 堆中有 stones[i] 块石头.每次移动(move)需要将连续的 K 堆石头合并为一堆,而这个移动的成本为这 K 堆石头的 ...

  3. LeetCode 1000. 合并石头的最低成本(区间DP)

    文章目录 1. 题目 2. 解题 1. 题目 有 N 堆石头排成一排,第 i 堆中有 stones[i] 块石头. 每次移动(move)需要将连续的 K 堆石头合并为一堆,而这个移动的成本为这 K 堆 ...

  4. LeetCode题解(1000):合并石头的最低成本(Python)

    题目:原题链接(困难) 标签:动态规划 解法 时间复杂度 空间复杂度 执行用时 Ans 1 (Python) O ( N 4 ) O(N^4) O(N4) O ( N 3 ) O(N^3) O(N3) ...

  5. 9.动态规划:区间DP问题(合并石头问题)【灵神基础精讲】

    0x3f:https://www.bilibili.com/video/BV1Gs4y1E7EU/ chenf99:由易到难,一步步说明思路和细节:https://leetcode.cn/proble ...

  6. 给定重量上限,背包问题_满足给定重量的袋子的最低成本

    给定重量上限,背包问题 Problem statement: 问题陈述: You are given a bag of size W kg and you are provided costs of ...

  7. 查找两个字符串中相同字符串_使两个字符串相同的最低成本

    查找两个字符串中相同字符串 Problem statement: 问题陈述: Given two strings string1 and string2 find the minimum cost r ...

  8. 畅通工程之最低成本建设问题 (30分)

    某地区经过对城镇交通状况的调查,得到现有城镇间快速道路的统计数据,并提出"畅通工程"的目标:使整个地区任何两个城镇间都可以实现快速交通(但不一定有直接的快速道路相连,只要互相间接通 ...

  9. 畅通工程之最低成本建设问题(30 分)

    这个题目就是一个最小生成树,如果无法构成就输出impossible ,就是构成最小生成树的时候,每选择一条边然后加加,最后统计是否有n-1条就可以. 最小生成树的讲解在我的其他的博客中有提到 #inc ...

最新文章

  1. 《数据库原理与应用》(第三版) 第 3 章 关系数据库 习题参考答案
  2. 利用有序节点来实现分布式锁
  3. Java程序和MySQL数据库中关于小数的保存问题
  4. 都啥年代了,求你别再说Redis是单线程了!
  5. 怎么能把你的公司快速做大呢
  6. 装饰者模式(Decorator pattern)
  7. 使用doxygen查看文件包含关系图
  8. 1006 换个格式输出整数 (15 分)—PAT (Basic Level) Practice (中文)
  9. eclipse黑色炫酷主题设置1
  10. python主函数的作用_Python中的main函数解析
  11. 在网站优化中怎么做好关键词密度?
  12. vue3项目打包优化三步走
  13. html5源码笔记(三)【爱创课堂专业前端培训】
  14. 【01】什么是 APP?移动 APP 有几种类型?
  15. 高仿《ONE一个》安卓APP
  16. 何谓OTA(Over-the-air programming)?
  17. 常见数据挖掘算法和Python简单实现
  18. 空间的一组基matlab,有关线性代数的Matlab代码笔记(2)——行空间、零空间
  19. 【半导体先进工艺制程技术系列】FinFET和UTB-SOI简介
  20. Android-x86 项目简介

热门文章

  1. 〖Python零基础入门篇⑩〗 - Python中的数字类型及应用
  2. 移动端图片_编码解码调研
  3. 利用反射及JDBC元数据编写通用的查询方法 cp66的头像 cp66 7 2015-02-13 23:16 0
  4. 通过JavaScript使div随时居中
  5. 用友软件T3出纳通提示单据锁定
  6. android 高仿资源合集~~
  7. 数据库建表原则和方式
  8. “The local variable XXX may not have been initialized”
  9. 看了林志颖的个人履历 我第一次被他震住了
  10. 缓存淘汰策略:LRU、LFU、FIFO 算法原理