LeetCode 312. Burst Balloons【区间DP】困难

news2024/11/17 15:57:53

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

有 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

解法1 递归+分治+记忆化搜索

对于气球,如果超出边界,那么就是左右各认为是 1 1 1 ,不妨直接在左右边界添加 1 1 1 ,形成一个连续的数组 r e f ref ref 。设 d f s ( i , j ) dfs(i,j) dfs(i,j) 为戳破 ( i , j ) (i, j) (i,j) 区间内所有气球获得的最大硬币数,原数组长度为 n n n ,本题答案即为 d f s ( 0 , n + 1 ) dfs(0, n+1) dfs(0,n+1)

现在,我们可以改变问题——在一排气球中,戳破气球 i , j i, j i,j 之间的所有气球(不包括 i , j i, j i,j ),使得最终只剩下两个气球 i , j i, j i,j ,最后能得到多少分

对于全开区间 ( i , j ) (i, j) (i,j) 的气球要全部戳破,不失一般性地考虑如何转移:

  • 递归边界或者基准情形: 0 ≤ i ≤ n + 1 ,   i ≤ j ≤ i + 1 0\le i \le n +1,\ i \le j \le i+1 0in+1, iji+1 ,这种情况下开区间 d f s ( i , j ) dfs(i,j) dfs(i,j) 中没有气球可以戳。
  • 其他情形: 要求出戳破气球 i i i 和气球 j j j 之间的最多硬币数,正向思考「第一个被戳破的气球是哪个」只能导向回溯解法,效率低。
    不难发现,最后会剩下两个气球 i , j i, j i,j ,而 ( i , j ) (i,j) (i,j) 中最后一个被戳破的气球假设为 k k k ,则戳破 k k k 获得的硬币数为 n u m s [ i ] × n u m s [ k ] × n u m s [ j ] nums[i] \times nums[k] \times nums[j] nums[i]×nums[k]×nums[j] 。此时 d f s ( i , j ) dfs(i,j) dfs(i,j) 可被分成两个规模更小、形式相似的子问题 d f s ( i , k ) ,   d f s ( k , j ) dfs(i, k),\ dfs(k, j) dfs(i,k), dfs(k,j)分而治之、分别递归求解。 d f s ( i , j ) = n u m s [ i ] × n u m s [ k ] × n u m s [ j ] + d f s ( i , k ) + d f s ( k , j ) dfs(i,j) = nums[i] \times nums[k] \times nums[j] + dfs(i, k) +dfs(k,j) dfs(i,j)=nums[i]×nums[k]×nums[j]+dfs(i,k)+dfs(k,j)
    受到上面的启发,我们可以反向思考,想一下气球 i , j i, j i,j 之间最后一个被戳破的气球可能是哪个?其实气球 i , j i, j i,j 之间的所有气球都可能是最后被戳破的那一个!因此,对 ( i , j ) (i,j) (i,j) 间的所有下标 k k k 分别进行分治,比较得到的所有答案,选最大硬币数即可。

当然,这种写法必然存在大量重复的递归调用。而这里的递归函数是无副作用的,相同的入参必然会返回相同的结果,我们可以用记忆化搜索来优化。

class Solution {
public:
    int maxCoins(vector<int> nums) {
        vector<int> ref;
        ref.push_back(1);
        for (int i : nums) ref.push_back(i);
        ref.push_back(1); // 返回戳破(i,j)区间内所有气球得到的最大硬币数
        int dp[310][310]; memset(dp, 0, sizeof(dp));
        function<int(int,int)> dfs = [&](int i, int j) -> int { 
            if (i + 1 == j) return 0; // 空区间
            if (dp[i][j]) return dp[i][j];
            for (int k = i + 1; k < j; ++k) { // 最后戳破气球k得到的最大分数
                dp[i][j] = max(dp[i][j], ref[k] * ref[i] * ref[j] +
                    dfs(i, k) + dfs(k, j));
            }
            return dp[i][j];
        };
        return dfs(0, ref.size() - 1);
    }
};

解法2 动态规划

上述代码稍微修改,改为递推形式,就是动态规划:

class Solution {
public:
    int maxCoins(vector<int> nums) {
        vector<int> ref;
        ref.push_back(1);
        for (int i : nums) ref.push_back(i);
        ref.push_back(1); // 返回戳破(i,j)区间内所有气球得到的最大硬币数
        int dp[310][310]; memset(dp, 0, sizeof(dp)); 
        int m = ref.size();
        for (int len = 1; len <= m; ++len) {
            for (int i = 0; i < m; ++i) {
                int j = min(i + len, m - 1); 
                for (int k = i + 1; k < j; ++k) { // 戳破气球k得到的最大分数
                    dp[i][j] = max(dp[i][j], ref[k] * ref[i] * ref[j] +
                        dp[i][k] + dp[k][j]);
                }
            }
        }
        return dp[0][m - 1]; 
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/445438.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

校验规则引擎

目录 一 架构设计图 二 表设计及数据展示 三 顶层接口 四 压测结果 五 其他规则引擎比较 适用场景&#xff1a;校验场景以及使用该思想进行可视化配置化开发&#xff08;可大幅提高开发效率&#xff0c;长期维护简单&#xff09; 例如&#xff1a;履约系统下单中的校验&…

C++(初识结束)

目录 4缺省参数 4.1缺省参数的概念 4.2缺省参数分类 4.3缺省参数的应用 5.函数重载 5.1函数重载概念 5.2c支持函数重载的原理-名字修饰&#xff08;name Mangling&#xff09; 6.引用 6.1引用概念 6.2引用特性 6.3常引用 6.4使用场景 6.4.1做参数 6.4.2做返…

2023年4月-近期看书

复习书记 用于读书 文章目录 复习书记一、(2001)控制工程基础二、(3001)交通管理与控制三、(1001)英语 一、(2001)控制工程基础 学习这本书的前6章节。 参看视频链接&#xff1a; https://www.bilibili.com/video/BV1Sb411q7jU?p8&spm_id_frompageDriver&vd_source…

构建完善的帮助中心:降低企业客户服务成本,提高客户满意度

客户服务是企业成功的关键之一&#xff0c;一家公司的成功不仅仅取决于产品或服务的质量&#xff0c;还在于能否为客户提供优质的客户服务。随着现代科技的发展&#xff0c;企业需要面对越来越多的客户服务需求&#xff0c;不良的客户服务将对企业的声誉和业务产生严重的影响。…

马斯克爆料Twitter裁了八成员工;OpenAI CEO:GPT-5根本不存在;小鹏被曝年终奖打0.5折 | AI一周资讯

来源: AI前线 微信号&#xff1a;ai-front 整理 | 凌敏 微软宣布开源 Deep Speed Chat&#xff1b;消息称软银旗下 Arm 启动赴美 IPO&#xff1b;国家网信办出台生成式 AI 管理办法&#xff1b;前理想 AI 芯片一号位骄旸加入三星&#xff0c;负责组建 GPU 团队…… 资 讯 Op…

KHS灌装机西门子触摸屏维修6AV6545-6DB10-0BS0

KHS设备维修范围包括&#xff1a;KHS无菌灌装设备&#xff0c;KHS包装设备&#xff0c;PET瓶装机&#xff0c; KHS码垛设备&#xff0c; KHS灌装机。 科埃斯KHS灌装机西门子P350工控机常见故障现象 1、工控机开机有显示&#xff0c;但是屏幕很暗&#xff0c;用调亮度功能键调…

熵、贝叶斯、极大似然

熵及熵在机器学习中的作用 熵 reference&#xff1a;https://blog.csdn.net/tsyccnh/article/details/79163834 香农给熵的定义&#xff1a;无损编码事件信息的最小平均编码长度 直观理解熵的定义&#xff1a;表示某一件事的不确定性 I ( x 0 ) − l o g ( p ( x 0 ) ) I(…

【Java版oj】day37数据库连接池、mkdir

目录 一、数据库连接池 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 二、mkdir &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 一、数据库连接…

ChatGPT会如何改变制造业?

来源 | Smart Industry Edgenesis编译 ChatGPT最新版本的发布成为热门头条。OpenAI表示该版本的ChatGPT能够在多个专业测试中达到“人类水平”的表现&#xff0c;例如司法考试和SAT考试。不过&#xff0c;在工业领域中&#xff0c;ChatGPT能够发挥怎样的作用呢&#xff1f;Sma…

升级OpenSSH版本(安装telnet远程管理主机

目录 一.OpenSSH是什么&#xff1f; 二.升级OpenSSH版本至8.9 1.环境介绍 2.检查是否安装telnet 3.安装telnet服务 4.启动telnet服务 5.安全文件关闭或者修改(否则root无法telnet登录) 6.安装依赖包 7.备份原有SSH服务版本 8.下载OpenSSH升级所需安装包 9.删除现有…

MySQL索引失效的七大场景

文章目录 口诀初始化数据库索引失效七大场景模&#xff08;模糊查询&#xff09;型&#xff08;数据类型&#xff09;数&#xff08;函数&#xff09;或&#xff08;OR&#xff09;运&#xff08;运算&#xff09;最&#xff08;最左原则&#xff09;快&#xff08;查询数据量大…

接口自动化测试系统知识大全,你想要的全都有

目录 接口自动化测试的前景 接口自动化测试的方法 接口自动化测试怎么做 接口自动化测试工具有哪些? 接口自动化测试框架 接口自动化测试的前景 随着移动互联网、云计算和大数据等技术的不断发展&#xff0c;接口自动化测试在软件开发中的重要性越来越凸显。尤其是随着微…

typora导出PDF很慢的解决办法

Typora导出PDF文件一直卡住 以前可以导出&#xff0c;但突然导出错误 1、首先&#xff0c;查看服务中的Print Spooler是否打开&#xff0c;没有打开进行服务打开 2、打开后&#xff0c;再进行导出&#xff0c;不行的话&#xff0c;就是前面的打印进程阻塞 解决方法&#xff…

软件测试?月薪20k+?不会自动化测试的我真的很难....

做自动化测试后悔吗&#xff1f; 后悔&#xff0c;真的后悔&#xff01; 后悔没有早点学..... 虽然现在网上到处都在散播35的焦虑&#xff0c;姑且信之&#xff0c;那么反问你&#xff0c;如果你30岁了&#xff0c;那么给你5年&#xff0c;能够在某个领域成为专家呢&#xf…

计算广告(十七)

多渠道组合路径效率评价 ​ 编辑切换为居中 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 分析背景&#xff1a; 电商归因分析通常以 last_click 为基准&#xff0c;将成交转化归功于用户完成转化前的最近一个广告系列。然而&#xff0c;在此之前&a…

java--线程池

目录 1.线程池概 2 为什么要使用线程池 1创建线程问题 2解决上面两个问题思路&#xff1a; 3线程池的好处 4线程池适合应用场景 3 线程池的构造函数参数 1.corePoolSize int 线程池核心线程大小 2.maximumPoolSize int 线程池最大线程数量 3.keepAliveTime long 空闲…

Centos elasticsearch 8.7.0 集群搭建

Install Elasticsearch with RPM | Elasticsearch Guide [8.7] | Elastic 准备了3台centos&#xff0c;ip分别是&#xff1a; 1、192.168.1.103 2、192.168.1.148 3、192.168.1.192 开始安装第1个节点 1、 rpm --import https://artifacts.elastic.co/GPG-KEY-elasticse…

快速引用网站标题链接到Markdown

JS脚本 将JS脚本添加到书签栏&#xff0c;通过调用书签栏执行快速复制网页标题和链接 合成Markdown格式的方法&#xff1a; javascript:!function(a){var b document.createElement("textarea"),c document.getSelection();(b.textContent a),document.body.ap…

【C++】STL——vector 深度剖析 及 模拟实现

文章目录 前言1. vector的介绍及使用1.1 vector的介绍1.2 vector的使用1.2.1 构造函数1.2.2 vector对象的遍历1.2.3 vector的迭代器1.2.4 reserve和resize1.2.5 insert和erase1.2.6 vector< char > 能否替代string 2. vector的模拟实现2.1 STL_vector源码浏览2.2 vector的…

网络安全-网站后台的寻找+网页JS文件信息收集

网络安全-网站后台的寻找网页JS文件信息收集 前言 一&#xff0c;我也是初学者记录的笔记 二&#xff0c;可能有错误的地方&#xff0c;请谨慎 三&#xff0c;欢迎各路大神指教 四&#xff0c;任何文章仅作为学习使用 五&#xff0c;学习网络安全知识请勿适用于违法行为 学习网…