leetcode 困难 —— 戳气球(超详细思路)

2023-10-31

题目:
有 n 个气球,编号为 0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。
现在要求你戳破所有的气球。戳破第 i 个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1] 枚硬币。 这里的 i - 1 和 i + 1 代表和 i 相邻的两个气球的序号。如果 i - 1或 i + 1 超出了数组的边界,那么就当它是一个数字为 1 的气球。
求所能获得硬币的最大数量。

题解:
用 dp 求解,这个 dp 思路非常妙

假如存在一组气球 a b c d e f g h i j k,我们要求这个的结果
为了方便计算我们预处理成 1 a b c d e f g h i j k 1
这时候假如我们最后剩下了 e
那么是不是就相当于 [ (1) a b c d (e) 的结果] + [ (e) f g h i j k (1) 的结果] + [ 1 * e * 1 ]

(这样的前提是什么呢,就是因为如果已知 e 是最后剩下的,那么这两段的最优情况是互不干扰的,所以这两个部分加上最后剩下的气球得到的值,就是最优解,所以满足最关键的 每个子问题的决策不能对后面其他未解决的问题产影响,无后效性

那么接下来比如我们看 (e) f g h i j k (1) 这一段
是不是也和最开始的情况一样
假如最后剩下的是 i
相当于 [ (e) f g h (i) ] + [ (i) j k (1) ] + [ (e) * i * (1) ]

由此可以得出可以得出公式
dp [ i ] [ j ] = dp [ i ] [ k - 1 ] + dp [ k + 1 ] [ j ] + val [ i - 1 ] * val [ j + 1 ] * val [ k ]

那么我们就可以开始写代码了,附上

class Solution {
public:
    int dp[305][305];
    int maxCoins(vector<int>& nums) {
        int n = nums.size();
        nums.insert(nums.begin(), 1);
        nums.push_back(1);
        for(int l = 0; l < n; l++) {
            for(int i = 1; i + l <= n; i++) {
                for(int k = i; k <= i + l; k++) {
                    dp[i][i+l] = max(dp[i][i+l], nums[k] * nums[i-1] * nums[i+l+1] + dp[i][k-1] + dp[k+1][i+l]);
                }
            }
        }
        return dp[1][n];
    }
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

leetcode 困难 —— 戳气球(超详细思路) 的相关文章

随机推荐