戳气球
难度:
标签:
题目描述
有 n
个气球,编号为0
到 n - 1
,每个气球上都标有一个数字,这些数字存在数组 nums
中。
现在要求你戳破所有的气球。戳破第 i
个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1]
枚硬币。 这里的 i - 1
和 i + 1
代表和 i
相邻的两个气球的序号。如果 i - 1
或 i + 1
超出了数组的边界,那么就当它是一个数字为 1
的气球。
求所能获得硬币的最大数量。
示例 1:
输入:nums = [3,1,5,8] 输出:167 解释: nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> [] coins = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = 167
示例 2:
输入:nums = [1,5] 输出:10
提示:
n == nums.length
1 <= n <= 300
0 <= nums[i] <= 100
代码结果
运行时间: 1095 ms, 内存: 17.9 MB
/*
* 思路:
* 1. 使用动态规划的方式解决该问题,但是使用Java Stream来进行数据的处理。
* 2. 依旧是使用 dp 数组来存储每个区间内的最大硬币数。
* 3. 通过Stream API进行数据流式处理,代码会更加简洁和直观。
*/
import java.util.Arrays;
public class BurstBalloonsStream {
public int maxCoins(int[] nums) {
int n = nums.length;
int[] newNums = new int[n + 2];
newNums[0] = 1;
newNums[n + 1] = 1;
System.arraycopy(nums, 0, newNums, 1, n);
int[][] dp = new int[n + 2][n + 2];
Arrays.stream(dp).forEach(row -> Arrays.fill(row, 0));
for (int length = 1; length <= n; length++) {
for (int left = 1; left <= n - length + 1; left++) {
int right = left + length - 1;
int l = left, r = right;
dp[left][right] = Arrays.stream(newNums, left, right + 1)
.map(k -> dp[left][k - 1] + newNums[left - 1] * k * newNums[right + 1] + dp[k + 1][right])
.max()
.orElse(0);
}
}
return dp[1][n];
}
}
解释
方法:
这个题解使用动态规划来解决戳气球问题。主要思路是:考虑最后戳破的气球是哪个,假设是第 k 个气球,那么状态转移方程就是 dp[i][j] = max(dp[i][k] + dp[k][j] + nums[i] * nums[k] * nums[j]),其中 dp[i][j] 表示戳破 (i, j) 范围内的所有气球能得到的最大硬币数,k 是 (i, j) 范围内最后一个戳破的气球。根据状态转移方程写出代码即可。
时间复杂度:
O(n^3)
空间复杂度:
O(n^2)
代码细节讲解
🦆
为什么在解题时选择动态规划方法而非贪心或回溯算法?
▷🦆
在动态规划的过程中,如何确保所有情况都被考虑到,特别是在选择最后一个戳破的气球k时?
▷🦆
动态规划数组`dp`的初始化为什么是0,这是否意味着在任何开始和结束位置之间没有气球的情况下硬币数为0?
▷🦆
题解中提到加入两个值为1的气球来简化边界条件,这种处理方式是否会影响最终的最大硬币计算?
▷相关问题
合并石头的最低成本
有 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,这是可能的最小值。
示例 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,这是可能的最小值。
提示:
n == stones.length
1 <= n <= 30
1 <= stones[i] <= 100
2 <= k <= 30