区间DP (Java) 解析/模板/案例

news2025/1/11 15:02:53

一. 区间DP简单介绍

        区间DP,是经常会用到的、解决区间问题的一种方法,经常以动态规划(dfs/记忆化搜索)的形式展现,最核心的思想就是枚举区间(枚举端点),寻找切割点,处理因切割点而产生的结果,进行区间累加或者选取个别区间,从而解决整体的问题。

二. 区间DP模板

枚举区间 

class Solution {
    public int 区间dp(int[] v) {
        int n = v.length;
        int[][] dp = new int[n][n];
        //枚举区间长度
        for(int len = 满足题目要求的最小值; len <= n; len++){
            //枚举左端点
            for(int L = 0; L+len-1 < n; L++){
                //枚举右端点
                int R = L + len - 1;
                //设置动态规划数组的初始值
                dp[L][R] = maxvalue;
                or
                dp[L][R] = minvalue;
                //枚举区间内的可能的切割点
                for(int k = L+1; k < R; k++){
                    dp[L][R] = Math.min(dp[L][R], dp[L][k] ? dp[k][R] ? 因切割点而产生的特殊值);
                }
            }
        }
        //返回规定的区间范围
        return dp[0][n-1];
        or
        return dp[1][n]
        or
        others
    }
}

枚举端点

枚举端点的方法和枚举区间本质上都一样,有些题目反而用枚举端点的方法更容易思考

class Solution {
    public int 区间dp(int[] v) {
        int[][] dp = new int[v.length][v.length];
        //枚举左端点,左端点经常从大到小枚举,为什么请看下文
        for(int i = v.length-3; i >= 0; i--){
            //枚举右端点
            for(int j = i+2; j < v.length; j++){
                //dp数组初始值
                dp[i][j] = Integer.MAX_VALUE;
                or
                dp[i][j] = Integer.MIN_VALUE;
                //枚举切割点
                for(int k = i+1; k < j; k++){
                    dp[i][j] = Math.min(dp[i][j],dp[i][k]?dp[k][j]?因切割点而产生的特殊值);
                }  
            }
        }
        return dp[0][v.length-1];
    }
}

三. 区间DP经典案例

1.leetcode1312 让字符串成为回文串的最少插入次数

给你一个字符串 s ,每一次操作你都可以在字符串的任意位置插入任意字符。

请你返回让 s 成为回文串的 最少操作次数 。

「回文串」是正读和反读都相同的字符串。

输入:s = "mbadm"
输出:2
解释:字符串可变为 "mbdadbm" 或者 "mdbabdm" 。

输入:s = "zzazz"
输出:0
解释:字符串 "zzazz" 已经是回文串了,所以不需要做任何插入操作。

 此问题和leetcode 516 最长回文子序列属于同类题目[Ref. 3]:

" 求的是将 s 变成回文串需要添加的最少字符数,所以我们只用求最长回文子序列长度即可,然后字符串 s 中除去最长回文子序列,剩下的字符就是不构成回文子序列的字符,添加与其同等数量的字符,将 s 构成回文串。"

**leetcode 516 最长回文子序列

给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

输入:s = "bbbab"
输出:4
解释:一个可能的最长回文子序列为 "bbbb" 。

输入:s = "cbbd"
输出:2
解释:一个可能的最长回文子序列为 "bb" 。
class Solution {
    public int longestPalindromeSubseq(String s) {
        int len = s.length();
        int[][] dp = new int[len][len];
        for(int i = len-1; i >= 0; i--){
            dp[i][i] = 1;
            for(int j = i+1; j < len; j++){
                if(s.charAt(i) == s.charAt(j)){
                    dp[i][j] = dp[i+1][j-1] + 2;
                }
                else{
                    dp[i][j] = Math.max(dp[i+1][j],dp[i][j-1]);
                }
            }
        }
        return dp[0][len-1];
    }
}

此题详解:

子串和子序列问题-动态规划向_子串 子序列_ForwardSummer的博客-CSDN博客

 再看此题

class Solution {
    public int minInsertions(String s) {
        int len = s.length();
        int[][] dp = new int[len+1][len+1];
        for(int i = len-1; i>= 0; i--){
            dp[i][i] = 1;
            for(int j = i+1; j < len; j++){
                if(s.charAt(i) == s.charAt(j)){
                    dp[i][j] = dp[i+1][j-1] + 2;
                }
                else{
                    dp[i][j] = Math.max(dp[i+1][j],dp[i][j-1]);
                }
            }
        }
        return len-dp[0][len-1];
    }
}

 本题小结:

(1)dp[i][j] 代表从i到j的区间(左闭右闭)内最长的回文子序列的长度

(2)那么,当s.charAt(i) == s.charAt(j),dp[i][j] = dp[i+1][j-1] + 2 

(3)当s.charAt(i) != s.charAt(j),dp[i][j] = Math.max(dp[i+1][j],dp[i][j-1]) 

(4) 字符串 s 中除去最长回文子序列,剩下的字符就是不构成回文子序列的字符

2.leetcode1039 多边形三角剖分的最低得分

你有一个凸的 n 边形,其每个顶点都有一个整数值。给定一个整数数组 values ,其中 values[i] 是第 i 个顶点的值(即 顺时针顺序 )。

假设将多边形 剖分 为 n - 2 个三角形。对于每个三角形,该三角形的值是顶点标记的乘积,三角剖分的分数是进行三角剖分后所有 n - 2 个三角形的值之和。

返回 多边形进行三角剖分后可以得到的最低分 。

1.边长为n的多边形形产生的三角形为n-2个,n>=3

2.当边为5时,固定一个边当作底(比如4-5),选择一个顶点(比如2),
  蓝色线表示的三角形将整个五边形分为三个部分。

3.当边长为5时,知道当前三角形面积(蓝色部分),知道左右的三角形面积,
  即可得到所有的三角形面积,进而求其和。

4.当来到多边形,依然找到一个三角形(求出其面积),将三角形左右两边求出(S1+S2),
  即可求所有的三角形构成的面积之和。

5.求出所有的可能性,选择其中一个最小的。

枚举左右端点 DFS


class Solution {
    int[] v;
    public int minScoreTriangulation(int[] v) {
        this.v = v;
        return dfs(0,v.length-1);
    }
    public int dfs(int i, int j){
        if(i+1 == j) return 0;
        int res = Integer.MAX_VALUE;
        for(int k = i+1; k < j; k++){
            res = Math.min(res,dfs(i,k)+dfs(k,j)+v[i]*v[j]*v[k]);
        }
        return res;
    }
}

本方法小结:

(1)dfs的意义代表从i端点到j端点构成的多边形的最小面积,相当于上图的{1~N+N~1}(顺时针)

(2)以i和j为底,k为顶点的三角形会把整个多边形分成更小的子问题

(3)左边的子问题为dfs(i,k),右边的子问题为dfs(k,j),已经解决的问题为当前这个三角形,即为v[i]*v[j]*v[k]

(4)当i+1 == j时,只有两个点,构不成三角形,返回0

 DFS超时,因为算法复杂度是O(n^3),数据很容易超时,接下来改成记忆化搜索。

记忆化搜索

class Solution {
    int[][] memo;
    int[] v;
    public int minScoreTriangulation(int[] v) {
        this.v = v;
        memo = new int[v.length][v.length];
        for(int[] i : memo){
            Arrays.fill(i,-1);
        }
        return dfs(0,v.length-1);
    }
    public int dfs(int i, int j){
        if(i+1 == j) return 0;
        if(memo[i][j] != -1) return memo[i][j];
        int res = Integer.MAX_VALUE;
        for(int k = i+1; k < j; k++){
            res = Math.min(res,dfs(i,k)+dfs(k,j)+v[i]*v[j]*v[k]);
        }
        memo[i][j] = res;
        return res;
    }
}

动态规划

class Solution {
    public int minScoreTriangulation(int[] v) {
        int[][] dp = new int[v.length][v.length];
        for(int i = v.length-3; i >= 0; i--){
            for(int j = i+2; j < v.length; j++){
                dp[i][j] = Integer.MAX_VALUE;
                for(int k = i+1; k < j; k++){
                    dp[i][j] = Math.min(dp[i][j],dp[i][k]+dp[k][j]+v[i]*v[j]*v[k]);
                }  
            }
        }
        return dp[0][v.length-1];
    }
}

本方法小结: 

(1)dp[i][j]代表从i到j区间内所构成的三角形面积的最小值

(2)i从length-3开始可以理解成 从i开始最少需要三条边构成三角形,j和k都比i要大,所以从i-3开始满足能成立一个三角形,j从i+2开始是因为中间需要留至少一个k的空间,最后k在i和j中取值,左虚右虚

(3)由于k比i大,而 dp[i][j]需要dp[i][k]作为基础,所以i的转移方向为从大到小,同理,j的方向为从小到大

经典枚举区间

class Solution {
    public int minScoreTriangulation(int[] v) {
        int n = v.length;
        int[][] dp = new int[n][n];
        for(int len = 3; len <= n; len++){
            for(int L = 0; L+len-1 < n; L++){
                int R = L + len - 1;
                dp[L][R] = 0x3f3f3f3f;
                for(int k = L+1; k < R; k++){
                    dp[L][R] = Math.min(dp[L][R], dp[L][k] + dp[k][R] + v[L]*v[R]*v[k]);
                }
            }
        }
        return dp[0][n-1];
    }
}

本方法小结:

(1)以上的方法都是枚举左右端点,此方法为经典的枚举区间

(2)区间长度len最少从3开始,长度大于等于3才能构成三角形,枚举左端点,右端点为左端点加上区间长度,然后枚举中间的k点(相当于三角形的顶点)

(3)一般的区间DP都是枚举区间,然后枚举左右端点,这题可以直接枚举左右端点,然后枚举中间的k点

参考来源Ref.

[1] leetcode 灵茶山艾府 【视频讲解】教你一步步思考动态规划!(Python/Java/C++/Go)

[2] leetcode Chisato 【视频讲解】教你一步步思考动态规划!(Python/Java/C++/Go)

[3] leetcode  return up; C++:动态规划(新瓶装旧酒)

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

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

相关文章

java.util.List和java.util.Set区别

最近有个需求要求查询按照单号查询顺序&#xff0c;数据库是hbase,我看了之前代码没有通过查hbase进行排序&#xff0c;就问了前端看是否前端可以排序&#xff0c;答案是前端不会做排序&#xff1b;有2个接口其中之前的接口就是这样排序的&#xff0c;于是我就按个排查看不同之…

Java每日一练(20230426)

目录 1. 天际线问题 &#x1f31f;&#x1f31f;&#x1f31f; 2. 2 的幂 &#x1f31f;&#x1f31f; 3. 对称二叉树 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每…

这可能是最全面的Redis面试八股文了

Redis连环40问&#xff0c;绝对够全&#xff01; Redis是什么&#xff1f; Redis&#xff08;Remote Dictionary Server&#xff09;是一个使用 C 语言编写的&#xff0c;高性能非关系型的键值对数据库。与传统数据库不同的是&#xff0c;Redis 的数据是存在内存中的&#xf…

jmeter(四)HTTP请求

启动jmeter&#xff0c;建立一个测试计划 这里再次说说怎么安装和启动jmeter吧&#xff0c;昨天下午又被人问到怎样安装和使用&#xff0c;我也是醉了&#xff1b;在我看来&#xff0c;百度能解决百分之八十的问题&#xff0c;特别是基础的问题。。。 安装&#xff1a;去官网…

状态设计模式解读

目录 问题引进 状态模式基本介绍 基本介绍 状态模式的原理类图 对原理类图的说明 状态模式解决 APP 抽奖问题 状态模式的注意事项和细节 问题引进 请编写程序完成 APP 抽奖活动 具体要求如下: 1) 假如每参加一次这个活动要扣除用户 50 积分&#xff0c;中奖概率是 10% …

尚融宝23-后端管理系统借款审核

目录 一、借款信息列表展示 &#xff08;一&#xff09;需求 &#xff08;二&#xff09;后端 &#xff08;三&#xff09;前端 二、借款详情 &#xff08;一&#xff09;需求 &#xff08;二&#xff09;后端 &#xff08;三&#xff09;前端 三、借款审批 &#xf…

YOLOv7训练自己的数据集(txt文件,笔记)

目录 1.代码下载 2.数据集准备&#xff08;.xml转.txt) &#xff08;1&#xff09;修改图像文件名 &#xff08;2&#xff09;图片和标签文件数量不对应&#xff0c;解决办法 &#xff08;3&#xff09;.xml转.txt &#xff08;4&#xff09;.txt文件随机划分出对应的训练…

记录自己第一次项目管理(附件:WBS计划与会议纪要模板)

记录自己第一次项目管理 前言 20**年新入职到一家公司&#xff0c;刚到就接到紧急任务&#xff0c;因为上一个后端跑路&#xff0c;现在系统上出现接口报错、假接口的问题&#xff0c;客户又着急验收&#xff0c;所以入职之后&#xff0c;一直在着急改代码。最后因为系统没有…

Nginx+Tomcat负载均衡及动态分离

一.Nginx负载均衡实现原理 Nginx实现负载均衡是通过反向代理实现 1、 反向代理原理 2、反向代理的概念 反向代理&#xff08;Reverse Proxy&#xff09;方式是指以代理服务器来接受internet上的连接请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;并将从服…

Promise--代码实现-- ajax 传统方式和 promise 方式和 promise 代码优化/重排 方式的对比--综合代码示例

目录 Promise Promise 基本介绍 Promise 应用实例 代码实现 monster.json monster_detail_1.json 先使用 ajax 传统方式完成, 问题分析(出现回调函数嵌套) 使用 promise 方式 示意图: 使用 promise 代码优化/重排 方式完成 get.js方法 注意事项和使用细节 综合代码 …

C语言学习分享(第五次)------函数

函数 1.前言2. 什么是函数3. 库函数3.1 为什么会有库函数3.2 如何学习库函数3.3 参考文档学习库函数3.31 strcpy函数3.32 memset函数3.33 使用库函数应该包含的头文件 4.自定义函数5.函数的参数5.1 交换两数题目详解 6. 函数的调用6.1 传址调用6.2 传值调用 7. 函数的嵌套调用和…

【机器学习】P25 随机森林算法(2) 实现 “波士顿房价” 预测

随机森林算法 Random Forest Algorithm 随机森林算法随机森林算法实现波士顿房价预测 随机森林算法 随机森林&#xff08;Random Forest&#xff09;算法 是一种 集成学习&#xff08;Ensemble Learning&#xff09;方法&#xff0c;它由多个决策树组成&#xff0c;是一种分类…

【RV1126】移植kaldi实时语音识别

文章目录 算法一、环境1.1 硬件环境--RV1126开发板1.2 交叉编译器1.3 需要Cmake版本大于3.1以上 二、交叉编译sherpa2.1 下载sherpa2.2 编译sherpa2.3 运行测试 三、下载模型四、语音测试4.1 单个语音文件解码测试4.2 开发板上使用alsa架构从MIC说话测试 算法 参考&#xff1a…

Mysql命令大全

一、mysql&#xff1a;连接Mysql数据库 mysql命令用户连接数据库。 mysql命令格式&#xff1a; mysql -h主机地址 -u用户名&#xff0d;p用户密码 连接到本机上的MYSQL 首先打开DOS窗口&#xff0c;然后进入目录mysql\bin&#xff0c;再键入命令mysql -u root -p&#xff0c;回…

开放式耳机有什么好处,分享几款知名度高的开放式耳机

开放式耳机是一种通过头骨传递声波的耳机&#xff0c;相比于传统的耳机&#xff0c;开放式耳机不用塞进耳道&#xff0c;而是在耳后的骨头里将声音传递到耳膜。而且因为不塞进耳朵&#xff0c;所以不用担心在使用过程中因为佩戴时间过长而导致的耳朵不适。所以相比于传统耳机来…

Linux-RaiDrive把ubuntu文件远程映射到Windows上

一、准备工作 系统&#xff1a;Ubuntu18.4 使用VMware安装Ubuntu虚拟机和VMware Tools_t_guest的博客-CSDN博客 Windows软件&#xff1a;RaiDrive 链接&#xff1a;https://pan.baidu.com/s/1t9lrC9lM_EXixmKYrQjfDg?pwd05ig 提取码&#xff1a;05ig 二、实操 1.设置语言 …

Ajax XHR readyState

文章目录 AJAX onreadystatechange 事件onreadystatechange 事件使用回调函数 AJAX onreadystatechange 事件 onreadystatechange 事件 当请求被发送到服务器时&#xff0c;我们需要执行一些基于响应的任务。 每当 readyState 改变时&#xff0c;就会触发 onreadystatechange…

记录6年时间3套easyui前端框架主题皮肤美化的设计历程

沉寂了许久&#xff0c;是该发点东西了&#xff0c;要不然2023年都要过去一半了 &#xff01; 第一次接触Easyui前端框架&#xff0c;还是在2016年的时候&#xff0c;有个美化easyui界面的需求&#xff0c;自己是设计师&#xff0c;前端知识也只会最基本的html和css样式&#x…

智慧班牌源码,使用springboot框架Java+vue2开发,二次开发方便快捷

智慧校园云平台电子班牌系统源码 智慧校园平台电子班牌系统源码在大数据平台下&#xff0c;对应用系统进行统一&#xff0c;以数据互联软硬结合的特点应用在校园&#xff0c;实现对校园、班级、教师、学生的管理。 智慧校园云平台电子班牌系统源码&#xff0c;使用springboot…

论文笔记:Map-Matching for low-sampling-rate GPS trajectories(ST-matching)

ACM-GIS 2019 1 Intro 将GPS数据和地图路网数据匹配提出全局地图匹配算法ST-matching&#xff08;类似于HMM的思路&#xff09; 考虑了道路网络的空间几何和拓扑结构 如果不考虑拓扑关系&#xff0c;直接进行matching的话&#xff0c;由于GPS信号的不准&#xff0c;可能轨迹会…