【力扣hot100】 312. 戳气球(区间dp)

一、题目

复制代码
有 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

二、思路

一开始就确定了是动态规划,但找不到切入的角度。想了二十分钟,怎么将这个问题拆为小问题。

猜测在中间取小,最后戳两边,尝试后才发现被自己做成贪心了。

于是看了题解,大多是用三重for循环,外两层控制区间,里一层枚举最后戳哪个

即从后往前推,例如:

先取区间(0,2),中间只有nums1,所以只能最后戳nums1,计算得出结果后max取大存入dp02。

然后再取区间(0,3),中间有nums1和nums2,假设最后戳nums1,则结果为dp01+dp13+nums0*nums1*nums2(前两者一者没有此情况,一者在上次循环就已经被计算);假设最后戳nums2,则结果为dp02+dp23+nums0*nums2*nums3(同理)。

这样就能逐步扩大区间,并在每个区间找到最大值。

三、尝试

通过的测试用例:12 / 73

完全错误的思路,属于是猜规律了。在情况不断变化的情况下,肯定是动态规划,而非贪心

cpp 复制代码
class Solution {
private:
    int _min;
    int sum=0;
public:
    int dp(vector<int>& nums,int n){
        if(n<=2){
            if(n==0) return 0;
            else if(n==1) sum+=1*nums[0]*1;
            else if(n==2) sum+=1*nums[0]*nums[1]+1*nums[1]*1;
            return sum;
        }
        else{
            _min=1;
            for(int i=2;i<n-1;i++){
                if(nums[_min]<=nums[i]) continue;
                else _min=i;
            }
            sum+=nums[_min-1]*nums[_min]*nums[_min+1];
            nums.erase(nums.begin()+_min);
            return dp(nums,n-1);
        }
    }
    int maxCoins(vector<int>& nums) {
        return dp(nums,nums.size());   
    }
};

四、题解

cpp 复制代码
class Solution {
private:
    vector<vector<int>> dp;
public:
    int maxCoins(vector<int>& nums) {
        nums.insert(nums.begin(),1);
        nums.push_back(1);
        dp=vector<vector<int>>(nums.size(),vector<int>(nums.size(),0));
        for(int left=nums.size()-2;left>=0;left--){
            for(int right=left+1;right<=nums.size()-1;right++){
                for(int last=left+1;last<right;last++){
                    dp[left][right]=max(dp[left][last]+dp[last][right]+nums[left]*nums[last]*nums[right],dp[left][right]);
                }
            }
        }
        return dp[0][nums.size()-1];
    }
};
相关推荐
CQU_JIAKE6 分钟前
10.1[A]2267,磐久UMX【上下文128K,KVCache部分]
算法
朝朝辞暮i11 分钟前
C++ 第 14 课:引用 &
开发语言·c++·算法
白山编程大哥22 分钟前
适合初学者练习的 C/C++ 开源项目推荐
c语言·c++·开源
Joe_Wang530 分钟前
【从0到1学习JVM · 21】既不浪费空间又没有碎片,标记整理算法到底慢在哪
jvm·学习·算法·垃圾回收·标记整理算法
让学习成为一种生活方式36 分钟前
PlantCellChat--单细胞与空间转录组数据预测植物细胞间通讯的R包--The Plant Journal
算法
C++ 老炮儿的技术栈1 小时前
有符号变量与无符号变量的区别
服务器·开发语言·前端·数据结构·c++·算法·c
个 人 练 习 生1 小时前
C++:模板初阶详解
开发语言·c++·经验分享·学习
梦帮科技1 小时前
多任务权重流形融合:SLERP 球形线性插值、DARE 稀疏剪枝与多专家模型融合落地
人工智能·深度学习·算法·机器学习·tensorflow·聚类·剪枝
Tisfy1 小时前
LeetCode 0020.有效的括号:栈匹配
算法·leetcode·字符串·题解·括号匹配
知识分享小能手1 小时前
C++ 学习教程,从入门到精通,C++类继承 — 完整知识点详解(13)
开发语言·c++·学习