312. 戳气球
有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。
现在要求你戳破所有的气球。戳破第 i 个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1] 枚硬币。 这里的 i - 1 和 i + 1 代表和 i 相邻的两个气球的序号。如果 i - 1或 i + 1 超出了数组的边界,那么就当它是一个数字为 1 的气球。
求所能获得硬币的最大数量。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/burst-balloons
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
区间[i, j]最后戳气球,枚举每个最后戳气球的位置
记忆化搜索
import java.util.Arrays;
class Solution {
private int[] nums;
private int[][] dp;
private int value(int index) {
if (index == -1 || index == nums.length) {
return 1;
}
return nums[index];
}
private int solve(int left, int right) {
if (left > right) {
return 0;
}
if (dp[left][right] != -1) {
return dp[left][right];
}
int ans = Integer.MIN_VALUE;
for (int i = left; i <= right; ++i) {
ans = Math.max(ans, value(left - 1) * value(i) * value(right + 1) + solve(left, i - 1) + solve(i + 1, right));
}
dp[left][right] = ans;
return dp[left][right];
}
public int maxCoins(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
this.nums = nums;
this.dp = new int[nums.length][nums.length];
for (int i = 0; i < nums.length; ++i) {
Arrays.fill(dp[i], -1);
}
return solve(0, nums.length - 1);
}
}
动态规划
class Solution {
private int[] nums;
private int value(int index) {
if (index == -1 || index == nums.length) {
return 1;
}
return nums[index];
}
private int dp() {
int n = nums.length;
int[][] dp = new int[n][n];
for (int left = n - 1; left >= 0; --left) {
dp[left][left] = value(left - 1) * value(left) * value(left + 1);
for (int right = left + 1; right < n; ++right) {
dp[left][right] = Math.max(dp[left + 1][right] + value(left - 1) * value(left) * value(right + 1),
dp[left][right - 1] + value(left - 1) * value(right) * value(right + 1));
for (int first = left + 1; first < right; ++first) {
dp[left][right] = Math.max(dp[left][right], dp[left][first - 1] + dp[first + 1][right] + value(left - 1) * value(first) * value(right + 1));
}
}
}
return dp[0][n - 1];
}
public int maxCoins(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
this.nums = nums;
return dp();
}
}
使用辅助数组
class Solution {
private int[][] dp;
private int solve(int[] helper, int left, int right) {
if (right - left <= 1) {
return 0;
}
if (dp[left][right] != -1) {
return dp[left][right];
}
int ans = Integer.MIN_VALUE;
for (int i = left + 1; i < right; i++) {
ans = Math.max(ans, helper[i] * helper[left] * helper[right] + solve(helper, left, i) + solve(helper, i, right));
}
dp[left][right] = ans;
return ans;
}
private int solve(int[] helper) {
int[][] dp = new int[helper.length][helper.length];
for (int left = helper.length - 3; left >= 0; left--) {
for (int right = left + 2; right < helper.length; right++) {
for (int k = left + 1; k < right; k++) {
dp[left][right] = Math.max(dp[left][right], helper[k] * helper[left] * helper[right] + dp[left][k] + dp[k][right]);
}
}
}
return dp[0][helper.length - 1];
}
public int maxCoins(int[] nums) {
int[] helper = new int[nums.length + 2];
helper[0] = helper[helper.length - 1] = 1;
for (int i = 1; i <= nums.length; i++) {
helper[i] = nums[i - 1];
}
// dp = new int[helper.length][helper.length];
// for (int[] d : dp) {
// Arrays.fill(d, -1);
// }
// return solve(helper, 0, helper.length - 1);
return solve(helper);
}
}
心之所向,素履以往 生如逆旅,一苇以航