LeetCode 312 Burst Ballons

思路

首先是brute-force暴力,直接dfs,复杂度O(n!)直接爆炸。

然后暴力+记忆化,取一个元素后断开的数组会连起来,状态过于复杂,即便可以记忆化复杂度也很大。

既然取的过程没法分解问题,那反过来思考,不断的取出等价于一个空数组不断地放回,放回的过程中,一旦某些元素确定位置,就会把整个数组划分成多个部分,因此也就可以对每个部分单独考虑,这样就把整个问题分成了几个子问题,这是分治和动态规划的前提。继续考虑容易想到,假设已经确定第一个放回的是第k个元素,那最终解即是 1 * nums[k] * 1 + solve[1~k-1] + [k+1~n]solve代表子问题的解。可以发现在放回的过程中记忆化能用了,但是需要解决几个小问题:

  1. solve[i~j]含义: solve表示区间i~j的最优解
  2. 状态转移(递推)过程: 如上solve[i][j] = solve[i][k-1] + solve[k+1][j] + nums[i-1] * nums[k] * nums[j+1]
  3. 假设对于某个区间i~j,第一个放回的是k,那么其代价是否一定是nums[i-1] * nums[k] * nums[j+1]?是的,考察到区间i~j时,该区间一定是由i-1j+1分割来得。

上述讨论均假设nums[-1] = nums[size] = 1,即原数组两边各有一个1。

之后就可以记忆化搜索或者动态规划了,这里给出动态规划的过程。

代码

class Solution {
public:
    int maxCoins(vector<int> &nums) {
        const size_t sz = nums.size();
#define multi(i, j, k) ((i > 0 ? nums[i - 1] : 1) * nums[k] * (j < sz - 1 ? nums[j + 1] : 1))
        if (sz == 0)
            return 0;
        else if (sz == 1)
            return nums[0];
        else if (sz == 2)
            return nums[0] * nums[1] + max(nums[0], nums[1]);
        int dp[501][501] = {};
        for (int i = sz - 1; i >= 0; i--) {
            dp[i][i] = multi(i, i, i);
            for (size_t j = i; j < sz; j++) {
                for (size_t k = i; k <= j; k++) {
                    dp[i][j] = max(dp[i][j], (k > 0 ? dp[i][k - 1] : 0) +
                                                 (k < sz - 1 ? dp[k + 1][j] : 0) + multi(i, j, k));
                }
            }
        }
#undef multi
        return dp[0][sz - 1];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值