动态规划算法专题(四):子串、子数组系列

目录

1、最大子数组和

1.1 算法原理

1.2 算法代码

2、环形子数组的最大和

2.1 算法原理

2.2 算法代码

3、乘积最大子数组

3.1 算法原理

3.2 算法代码

4、乘积为正数的最长子数组长度

4.1 算法原理

4.2 算法代码

5、等差数列划分

5.1 算法原理 

5.2 算法代码

6、最长湍流子数组

6.1 算法原理 

6.2 算法代码

7、单词拆分

7.1 算法原理

7.2 算法代码

8、环绕字符串中唯一的子字符串

8.1 算法原理 

 8.2 算法代码


1、最大子数组和

. - 力扣(LeetCode)

1.1 算法原理

  • 状态表示dp[i]:

以i位置为结尾,最长子序列之和

  • 状态转移方程:

dp[i]=max(dp[i-1]+nums[i-1],nums[i-1]);

  • 初始化:

int[] dp = new int[n+1];
dp[0]=0;

  • 填表顺序:

从左往右

  • 返回值:

dp中最大序列和

1.2 算法代码

class Solution {public int maxSubArray(int[] nums) {int n = nums.length;int[] dp = new int[n + 1];// 初始化dp[0] = 0;int ret = Integer.MIN_VALUE;// 填表for(int i = 1; i <= n; i++) {dp[i] = Math.max(dp[i - 1] + nums[i - 1], nums[i - 1]);ret = Math.max(ret, dp[i]);}return ret;}
}

2、环形子数组的最大和

. - 力扣(LeetCode)

2.1 算法原理

核心:将带环问题转化为普通不带环问题

  • 状态表示:

f[i]:以i位置为结尾,最大子序列之和
g[i]:以i位置为结尾,最小子序列之和

  • 状态转移方程:

f[i] = Math.max(f[i - 1] + nums[i - 1], nums[i - 1]);

g[i] = Math.min(g[i - 1] + nums[i - 1], nums[i - 1]);

  • 初始化:

下标映射:dp[i]-->nums[i-1]
虚拟节点:要保证后续填表的正确性:f[0]=g[0]=0;

  • 填表顺序:

从左往右,两个表一起填。

  • 返回值(特殊情况:当表中的数都是负数时(都在最小子序列中),此时sum-gMin=0):

找到f表中的最大值 fMax;
找到g表中的最小值 gMin,进而得到最大和序列:sum-gMin;
return sum == gMin ? fMax : max(fMax, sum-gMin);

2.2 算法代码

class Solution {public int maxSubarraySumCircular(int[] nums) {int n = nums.length;int sum = 0;for(int x : nums) sum += x;int[] f = new int[n + 1];//内部最大子数组int[] g = new int[n + 1];//内部最小子数组f[0] = g[0] = 0;int fMax = Integer.MIN_VALUE;int gMin = Integer.MAX_VALUE;for(int i = 1; i <= n; i++) {f[i] = Math.max(f[i - 1] + nums[i - 1], nums[i - 1]);g[i] = Math.min(g[i - 1] + nums[i - 1], nums[i - 1]);fMax = Math.max(fMax, f[i]);gMin = Math.min(gMin, g[i]);}// 注意数组中全是负数的情况return sum == gMin ? fMax : Math.max(fMax, sum - gMin);}
}

3、乘积最大子数组

. - 力扣(LeetCode)

3.1 算法原理

  • 状态表示:

f[i]:以i位置为结尾,最大乘积
g[i]:以i位置为结尾,最小乘积

  • 状态转移方程:

f[i]=max(nums[i-1], f[i-1]*nums[i-1], g[i-1]*nums[i-1]);
g[i]=min(nums[i-1], f[i-1]*nums[i-1], g[i-1]*nums[i-1]);

  • 初始化:

f[1]=g[1]=1;

  • 建表顺序:

从左往右,两个表一起填

  • 返回值:

f表中的最大值

3.2 算法代码

class Solution2 {public int maxProduct(int[] nums) {int n = nums.length;int[] f = new int[n + 1];// 以i位置为结尾,最大乘积int[] g = new int[n + 1];// 以i位置为结尾,最小乘积int ret = Integer.MIN_VALUE;// 初始化f[0] = g[0] = 1;// 建表for(int i = 1; i <= n; i++) {f[i] = Math.max(nums[i - 1], Math.max(nums[i - 1] * f[i - 1], nums[i - 1] * g[i - 1]));g[i] = Math.min(nums[i - 1], Math.min(nums[i - 1] * f[i - 1], nums[i - 1] * g[i - 1]));ret = Math.max(ret, f[i]);}return ret;}
}

4、乘积为正数的最长子数组长度

. - 力扣(LeetCode)

4.1 算法原理

  • 状态表示:

f[i]:以i位置为结尾,乘积为 正数 的,最长子序列的长度。

g[i]:以i位置为结尾,乘积为 负数 的,最长子序列的长度。

  • 状态转移方程:

①:nums[i] > 0

f[i] = f[i-1]+1; g[i] = (g[i-1]==0 ? 0 : g[i-1]+1);

②:nums[i] < 0

f[i] = (g[i-1]==0 ? 0 : g[i-1]+1); g[i] = f[i-1]+1;

  • 初始化:

①:f[0]=g[0]=0; // 虚拟节点的值,不影响后续填表的正确性

②:下标映射关系

  • 返回值:

f表中的最大值

4.2 算法代码

class Solution {public int getMaxLen(int[] nums) {int n = nums.length;int[] f = new int[n + 1];// 乘积为正数的最长序列的长度int[] g = new int[n + 1];// 乘积为负数的最长序列的长度int ret = 0;// 填表for(int i = 1; i <= n; i++) {if(nums[i - 1] > 0) {f[i] = f[i - 1] + 1;g[i] = (g[i - 1] == 0 ? 0 : g[i - 1] + 1);}if(nums[i - 1] < 0) {f[i] = (g[i - 1] == 0 ? 0 : g[i - 1] + 1);g[i] = f[i - 1] + 1;}ret = Math.max(ret, f[i]);}return ret;}
}

5、等差数列划分

. - 力扣(LeetCode)

5.1 算法原理 

  • 状态表示dp[i]:

以i位置为结尾的所有子序列中,等差序列(长度>=3)的数量

  • 状态转移方程:

①:nums[i]-nums[i-1] == nums[i-1]-nums[i-2] => dp[i]=dp[i-1]+1;

②:nums[i]-nums[i-1] != nums[i-1]-nums[i-2] => dp[i]=0;

  • 初始化:

dp[0]=dp[1]=0;(子序列长度不足3)

  • 返回值:

dp表之和

5.2 算法代码

class Solution {public int numberOfArithmeticSlices(int[] nums) {int n = nums.length;int[] dp = new int[n];int ret = 0;// 填表for(int i = 2; i < n; i++) {if(nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2]) {dp[i] = dp[i - 1] + 1;ret += dp[i];}}return ret;}
}

6、最长湍流子数组

. - 力扣(LeetCode)

6.1 算法原理 

  • 状态表示:

f[i]:以i位置为结尾,最后呈现"上升趋势"的最长子序列的长度
g[i]:以i位置为结尾,最后呈现"下降趋势"的最长子序列的长度

  • 状态转移方程:

if(nums[i] > nums[i-1]) f[i]=g[i-1]+1;
if((nums[i] < nums[i-1]) g[i]=f[i-1]+1;

  • 初始化:

f表,g表中所有元素的值初始化为 1 
(最差情况序列长度为1)

  • 建表顺序:

从左往右

  • 返回值:

f 和 g 表中的最大值

6.2 算法代码

class Solution {public int maxTurbulenceSize(int[] arr) {int n = arr.length;int[] f = new int[n];// f[i]: 最后呈现"上升"趋势的最长湍流子数组的长度int[] g = new int[n];// g[i]: 最后呈现"下降"趋势的最长湍流子数组的长度// 初始化Arrays.fill(f, 1);Arrays.fill(g, 1);int ret = 1;// 建表 + 处理返回值for(int i = 1; i < n; i++) {if(arr[i] > arr[i - 1]) f[i] = g[i - 1] + 1;if(arr[i] < arr[i - 1]) g[i] = f[i - 1] + 1;ret = Math.max(ret, Math.max(f[i], g[i]));}return ret;}
}

7、单词拆分

. - 力扣(LeetCode)

7.1 算法原理

  • 状态表示dp[i]:

[0, i]区间的字符串,能否被字典中的单词拼接而成

  • 状态转移方程:

根据最后一个单词的位置,划分问题。
设j为最后一个单词的起始位置(0<=j<=i),
判断条件①:[j, i]区间的字符串是否存在于字典中
判断条件②:[0, j-1]区间的字符串是否可被拼接而成

  • 初始化:

 dp[0]=true;(里面的值要保证后续的填表是正确的)
 优化:s = s+ " ";(下标映射的处理)

  • 填表顺序:

从左往右

  • 返回值:

dp[n];

7.2 算法代码

class Solution {public boolean wordBreak(String s, List<String> wordDict) {// 优化一:哈希Set<String> hash = new HashSet<>(wordDict);int n = s.length();boolean[] dp = new boolean[n + 1];s = " " + s;// 初始化dp[0] = true;for(int i = 1; i <= n; i++) {for(int j = i; j >= 1; j--) {if(hash.contains(s.substring(j, i + 1)) && dp[j - 1]) {dp[i] = true;// 优化二break;}}}return dp[n];}
}

8、环绕字符串中唯一的子字符串

. - 力扣(LeetCode)

8.1 算法原理 

  • 状态表示:

以i位置字符为结尾的所有不同的子串,有多少个在base中出现过

  • 状态转移方程:

if(s[i-1]+1 == s[i] || (s[i-1] == 'z' && s[i] == 'a')) --> dp[i] += dp[i-1];

  • 初始化:

Arrays.fill(dp, 1);// 最差情况下,字符本身构成base中的子串

  • 填表顺序:

从左往右

  • 返回值:

给重复的子串去重:
相同字符结尾的dp值,取最大的即可(虽然是相同字符结尾的子串,但dp值更大的这种情况,
包含了dp值小的情况):
1. int[26] hash // 存相应字符结尾的最大的dp值
2. 返回hash数组的和

 8.2 算法代码

class Solution {public int findSubstringInWraproundString(String ss) {char[] s = ss.toCharArray();int n = s.length;// 状态表示:以i位置字符为结尾的所有不同的子串,有多少个在base中出现过int[] dp = new int[n];int[] hash = new int[26];Arrays.fill(dp, 1);// 填表for(int i = 1; i < n; i++) {if(s[i - 1] + 1 == s[i] || (s[i - 1] == 'z' && s[i] == 'a')) {dp[i] += dp[i - 1];}}// 去重for(int i = 0; i < n; i++) {int index = s[i] - 'a';hash[index] = Math.max(hash[index], dp[i]);}// 返回结果int ret = 0;for(int x : hash) ret += x;return ret; }
}

END

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

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

相关文章

COSPLAY大赛静态HTML网页模板源码

源码名称&#xff1a;COSPLAY大赛静态HTML网页模板 源码介绍&#xff1a;一款cosplay大赛HTML网页模板源码&#xff0c;过往参赛选手会自动从腾讯大赛获取&#xff0c;可用于cosplay大赛&#xff0c;漫展等。 需求环境&#xff1a;H5 下载地址&#xff1a; https://www.5188…

k8s的控制节点不能访问node节点容器的ip地址

master控制node服务器添加容器后,访问不了该node服务器容器的ip,只能在node服务器访问 排查后发现是k8s的master服务器和node节点的网址网段和k8s初始化时提示的ip网段不一致 我之前是192.168.137.50, 实际上master主机期望的是192.168.1.50 解决方案: 1.删除服务器后重建ma…

【api连接ChatGPT的最简单方式】

通过api连接ChatGPT的最简单方式 建立client 其中base_url为代理&#xff0c;若连接官网可省略&#xff1b;配置环境变量 from openai import OpenAI client OpenAI(base_url"https://api.chatanywhere.tech/v1" )或给出api和base_url client OpenAI(api_key&…

Redis:string类型

Redis&#xff1a;string类型 string命令设置与读取SETGETMSETMGET 数字操作INCRINCRBYDECRDECRBYINCRBYFLOAT 字符串操作APPENDSTRLENGETRANGESETRANGE 内部编码intembstrraw 在Redis中&#xff0c;字符串string存储的是二进制&#xff0c;以byte为单位&#xff0c;输入的二进…

Pikachu-Unsafe FileUpload-客户端check

上传图片&#xff0c;点击查看页面的源码&#xff0c; 可以看到页面的文件名校验是放在前端的&#xff1b;而且也没有发起网络请求&#xff1b; 所以&#xff0c;可以通过直接修改前端代码&#xff0c;删除 checkFileExt(this.value) 这部分&#xff1b; 又或者先把文件名改成…

java代理模式(动态代理、静态代理、需要实现类的JDK代理、不需要实现类的JDK动态代理、CGLIB代理)

静态代理简单使用 静态代理是代理模式的一种实现方式&#xff0c;它在编译时就已经确定了被代理对象和代理对象的关系。在静态代理中&#xff0c;需要手动创建一个代理类&#xff0c;该代理类与被代理对象实现相同的接口或继承相同的父类&#xff0c;并在代理类的方法中调用被…

C++基类构造器的自动调用

C基类构造器的自动调用 虽然基类的构造器和解构器不会被派生类继承&#xff0c;但它们会被派生类的构造器和解构器自动调用&#xff0c;今天我们用代码实证一下。 验证代码 源代码&#xff0c;仔细看注释内容&#xff1a; D:\YcjWork\CppTour>vim c2004.cpp #include &l…

《RabbitMQ篇》基本概念介绍

MQ功能 解耦 MQ允许不同系统或组件之间松散耦合。发送者和接收者不需要直接连接&#xff0c;从而提高了系统的灵活性和可维护性。异步处理 使用MQ可以实现异步消息传递&#xff0c;发送者可以将消息放入队列后立即返回&#xff0c;不必等待接收者处理。这提高了系统的响应速度…

Windows下Jenkins控制台中文乱码

问题描述 问题情况如下图&#xff1a; 环境信息 Windows 11 家庭中文版java 21.0.4 2024-07-16 LTSJenkins 2.452.3 解决方法 增加系统JAVA_TOOL_OPTIONS&#xff0c;并设置值为-Dfile.encodingGBK。 打开设置方法&#xff1a;桌面上右键点击“此电脑”图标&#xff0c;选…

算法笔记(十三)——BFS 解决最短路问题

文章目录 迷宫中离入口最近的出口最小基因变化单词接龙为高尔夫比赛砍树 BFS 解决最短路问题 BFS(广度优先搜索) 是解决最短路径问题的一种常见算法。在这种情况下&#xff0c;我们通常使用BFS来查找从一个起始点到目标点的最短路径。 迷宫中离入口最近的出口 题目&#xff1a;…

Android SystemUI组件(11)SystemUIVisibility解读

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节思维导图&#xff0c;主要关注左侧最上方SystemUiVisibility解读部分即可。 本章节主要讲解SystemUiVisibility的概念及其相…

数据库(MySQL):使用命令从零开始在Navicat创建一个数据库及其数据表(一).创建基础表

一. 使用工具和命令 1.1 使用的工具 Navicat Premium 17 &#xff1a;“Navicat”是一套可创建多个连接的数据库管理工具。 MySQL版本8.0.39 。 1.2 使用的命令 Navicat中使用的命令 命令命令解释SHOW DATABASES&#xff1b;展示所有的数据库CREATE DATABASE 数据库名称; 创…

thinkphp 学习记录

1、PHP配置 &#xff08;点开链接后&#xff0c;往下拉&#xff0c;找到PHP8.2.2版本&#xff0c;下载的是ZIP格式&#xff0c;解压即用&#xff09; PHP For Windows: Binaries and sources Releases &#xff08;这里是下载地址&#xff09; 我解压的地址是&#xff1a;D:\…

1、如何查看电脑已经连接上的wifi的密码?

在电脑桌面右下角的如下位置&#xff1a;双击打开查看当前连接上的wifi的名字&#xff1a;ZTE-kfdGYX-5G 按一下键盘上的win R 键, 输入【cmd】 然后&#xff0c;按一下【回车】。 输入netsh wlan show profile ”wifi名称” keyclear : 输入完成后&#xff0c;按一下回车&…

中断系统的原理

一、介绍 中断是为使单片机具有对外部或内部随机发生的事件实时处理而设置的。中断是指‌CPU在正常运行程序时&#xff0c;由于内部或外部事件的发生&#xff0c;导致CPU中断当前运行的程序&#xff0c;转而去执行其他程序的过程。‌ 中断可以是硬件产生的&#xff0c;也可以是…

安全运营中心 (SOC) 团队对其安全工具感到失望

Vectra AI 表示&#xff0c;安全运营中心 (SOC) 从业人员认为&#xff0c;由于太多孤立的工具和缺乏准确的攻击信号&#xff0c;他们在检测和确定真实威胁的优先级方面正在失败。 人们对供应商的不信任感日益加深&#xff0c;认为供应商的工具在发现真正的攻击方面起的阻碍作用…

金纳米星“融入”水凝胶,原位生长的奥秘,应用前景的探索

大家好&#xff01;今天来了解一项在三维水凝胶表面生长金纳米星的研究——《Growing Gold Nanostars on 3D Hydrogel Surfaces》发表于《Chemistry of Materials》。水凝胶在生物医学等诸多领域有着重要应用&#xff0c;而金纳米星具有独特的光学性质。这项研究通过原位合成的…

【Linux】线程与线程安全知识总结

向外张望的人在做梦&#xff0c; 向内审视的人才是清醒的。 --- 荣格 --- 我最近复习了线程安全这部分知识&#xff0c;将不明白的问题总结出来&#xff0c;并通过AI进行问答帮助我进行学习巩固。本人能力有限 &#xff0c;可能有些内容不准确&#xff0c;望各位大佬海涵&am…

【前端开发入门】css快速入门

目录 引言一、css盒模型1. 盒模型概念2. 盒模型案例 二、css编写1. html文件内部编写1.1 标签style属性编写1.2 css选择器关联1.2.1 id选择器1.2.2 class选择器1.2.3 标签选择器1.2.4 css选择器作用域1.2.5 其他选择器1.2.6 各css选择器优先级 2. 单独维护css文件2.1 创建css文…

HDLBits中文版,标准参考答案 | 3.1.4 Karnaugh Map to Circuit | 卡诺图到电路

关注 望森FPGA 查看更多FPGA资讯 这是望森的第 11 期分享 作者 | 望森 来源 | 望森FPGA 目录 1 3 变量 2 4 变量 3 4 变量 4 4 变量 5 最小 SOP 和 POS 6 卡诺图 7 卡诺图 8 使用多路复用器实现的卡诺图 本文中的代码都能够正常运行&#xff0c;请放心食用&#x1f…