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

一. 区间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++:动态规划(新瓶装旧酒)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

并发编程基石:管程

大家好&#xff0c;我是易安&#xff01; 如果有人问我学习并发并发编程&#xff0c;最核心的技术点是什么&#xff0c;我一定会告诉他&#xff0c;管程技术。Java语言在1.5之前&#xff0c;提供的唯一的并发原语就是管程&#xff0c;而且1.5之后提供的SDK并发包&#xff0c;也…

手写Spring框架---IOC容器实现

目录 框架具备的最基本功能 实现容器前奏 创建注解 提取标记对象 extractPacakgeClass里面需要完成的事情 获取项目类加载器的目的 为什么不让用户传入绝对路径 类加载器ClassLoader 统一资源定位符URL ClassUtil提取标记类 获取包下类集合 装载目标类的集合 获取…

【Unity入门】21.预制体

【Unity入门】预制体 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity入门系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;一&#xff09;预制体制作 &#xff08;1&#xff09;什么是预制体 这一章节的博客&#xff0c;我们将会学习一个预制体的概念。什么是…

【C语言】struct结构体

文章目录 一. 结构体简述二. 结构体的声明和定义1、简单地声明一个结构体和定义结构体变量2、声明结构体的同时也定义结构体变量3、匿名结构体4、配合typedef&#xff0c;声明结构体的同时为结构体取别名5、在声明匿名结构体时&#xff0c;使用typedef给这个匿名结构体取别名 三…

中国的chatGpt-中国chatGPT软件

chatGPT中文免费版 您是否在寻找一款免费且实用的聊天软件来更好地与别人交流&#xff1f;那么&#xff0c;“chatGPT中文免费版”将是您的不二选择&#xff01; 作为一款由 OpenAI 训练的大型语言模型&#xff0c;chatGPT 中文免费版可以让您轻松地与其他人进行交流&#xf…

( 栈和队列) 155. 最小栈 ——【Leetcode每日一题】

❓155. 最小栈 难度&#xff1a;中等 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void pop() 删除堆栈顶部的元素。…

计算机网络【2】 子网掩码

学习大佬记下的笔记 https://zhuanlan.zhihu.com/p/163119376 "子网"掩码&#xff0c;顾名思义&#xff0c;它就是拿来划分子网的&#xff0c;更准确的说&#xff0c;划分子网的同时&#xff0c;还能通过它知道主机在子网里面的具体ip的具体地址。 子网掩码只有一个…

Pytest接口自动化测试实战演练

结合单元测试框架pytest数据驱动模型allure 目录 api&#xff1a; 存储测试接口conftest.py :设置前置操作目前前置操作&#xff1a;1、获取token并传入headers&#xff0c;2、获取命令行参数给到环境变量,指定运行环境commmon&#xff1a;存储封装的公共方法connect_mysql.p…

【计算机是怎么跑起来的】基础:计算机三大原则

【计算机是怎么跑起来的】基础&#xff1a;计算机三大原则 计算机的三个根本性基础1.计算机是执行输入&#xff0c;运算&#xff0c;输出的机器输入&#xff0c;运算&#xff0c;输出 2. 软件是指令和数据的集合指令数据 3. 计算机的处理方式有时与人们的思维习惯不同对计算机来…

如何做好采购计划和库存管理?

“销售计划不专业且不稳定”“准确性低” “目前只按照过往销量和采购周期做安全库存&#xff0c;但欠货和滞销依然严重” 题主的问题其实蛮有代表性的&#xff0c; 也是传统采购和库存管理常常面临的问题&#xff1a; ① 前后方协作困难 采购/销售/财务工作相互独立&#x…

NetXpert XG2帮您解决“布线安装与维护”难题

在传输大量数据时&#xff0c;光纤变得越来越重要&#xff0c;而铜缆在未来也将继续发挥重要作用&#xff0c;因此我们不仅要比较两种类型布线的优缺点&#xff0c;还要探究光纤传输中的错误来源。 测试光缆传输损耗的准确性对于故障排除至关重要&#xff0c;特别是在光纤情况下…

2023五一数学建模竞赛(五一赛)选题建议

提示&#xff1a;DS C君认为的难度&#xff1a;C<A<B&#xff0c;开放度&#xff1a;B<A<C 。 A题&#xff1a;无人机定点投放问题 这道题是传统的物理类题目&#xff0c;基本每次建模竞赛都会有。由于这道题目并未给明数据&#xff0c;所以数据获取和搜集资料是…

来了来了,我使用 ChatGPT 开发了一个 AI 应用

ChatGpt 实在太火爆了&#xff0c;很多人在问我怎么使用 chatgpt 开发一个 AI 应用程序。这不就来了吗~ 开始 你所需要准备的一个OpenAI 的密钥和一点点代码来发送提示并返回结果&#xff0c;例如下面这段代码&#xff1a; import { OpenAIApi, Configuration } from openai…

超火爆的ChatGPT课,送ChatGPT账号啦~~

HOT! HOT! HOT! &#x1f525; &#x1f525; &#x1f525; 上周&#xff0c;ChatGPT全栈开发课程一经推出&#xff0c;就在程序员圈子中引起了广泛关注。这两天 都被挤爆了&#xff0c;纷纷表示对课程内容很是期待呢。 明天就要开班直播啦&#xff0c;还未报名的同学&…

神经网络模型入门及蠓虫分类问题简单实战

学习知识要实时简单回顾&#xff0c;我把学习的神经网络模型简单梳理一下&#xff0c;方便入门与复习。 神经网络模型 神经网络简介 人工神经网络是在现代神经科学的基础上提出和发展起来的&#xff0c;旨在反映人脑结构及功能的一种抽象数学模型。自 1943 年美国心理学家W.M…

第十四章 代理模式

文章目录 前言一、静态代理完整代码接口 ITeacherDao &#xff08;代理类和被代理类都需要实现这个接口&#xff09;被代理类 TeacherDao代理类 TeacherDaoProxy测试类 Client 二、JDK动态代理完整代码接口 ITeacher实现类TeacherDao代理工厂 ProxyFacyoryclient 测试 三、Cgli…

企业本地文档如何实现规范在线管理?

随着企业数字化生产方式的不断推进&#xff0c;网络办公和在线协作越来越普遍&#xff0c;企业内部可能出现大量的文件和文档&#xff0c;这些文档多存在于不同的设备和存储介质上&#xff0c;这给企业的信息管理带来了一定程度的困难。为了提高企业的知识管理效率&#xff0c;…

Go基础篇:类型系统

目录 前言✨一、什么是类型&#xff1f;二、类型特性1、静态类型检查2、类型推断 三、类型别名和自定义类型1、类型别名2、自定义类型3、类型别名和自定义类型的区别 四、类型底层结构1、类型元数据2、其他描述信息3、uncommontype 五、小结 前言✨ 前段时间忙着春招面试&#…

移动端事件

文章目录 移动端事件概述兼容性Touch触摸事件事件类型是否支持事件使用event对象touch对象阻止浏览器默认行为单指拖拽 Pointer指针事件事件类型是否支持事件使用event对象阻止浏览器默认行为单指拖拽 移动端事件 概述 移动端事件可分为&#xff1a; Touch触摸事件Pointer指…

【Bard】谷歌的人工智能工具—Bard初体验

文章目录 一、Bard介绍二、Bard体验1、加入Bard的候补名单2、登入Bard篇3、使用Bard篇&#xff08;1&#xff09;提供三种预选方式✨&#xff08;2&#xff09;创作生成各类文案&#xff08;3&#xff09;无生成图画能力&#xff08;4&#xff09;支持语音转文本输入✨&#xf…