[dp8_子数组] 乘积为正数的最长子数组长度 | 等差数列划分 | 最长湍流子数组

news2025/4/15 22:40:36

目录

1.乘积为正数的最长子数组长度

2.等差数列划分

3.最长湍流子数组


  • 写代码做到,只用维护好自己的一小步

1.乘积为正数的最长子数组长度

链接:1567. 乘积为正数的最长子数组长度

给你一个整数数组 nums ,请你求出乘积为正数的最长子数组的长度。

一个数组的子数组是由原数组中零个或者更多个连续数字组成的数组。

请你返回乘积为正数的最长子数组长度。

示例 1:

输入:nums = [1,-2,-3,4]
输出:4
解释:数组本身乘积就是正数,值为 24 。

示例 2:

输入:nums = [0,1,-2,-3,-4]
输出:3
解释:最长乘积为正数的子数组为 [1,-2,-3] ,乘积为 6 。
注意,我们不能把 0 也包括到子数组中,因为这样乘积为 0 ,不是正数。

  • 在上一题当中我们求过了,乘积最大的子数组,现在我们找的是乘积为正数的,最长的子数组
  • 我们该如何分析这个状态呢

求乘积为正数最大子数组长度。


1.状态表示

  • 经验 + 题目要求
  • dp[i] 表示 :以 i 位置元素为结尾的所有子数组中乘积为正数的最大长度

还是先以这个分析

  • i 本身也是子数组,然后为空看nums[i] 是正还是负。
  • 还有以 i 位置为结尾的子数组,求所有子数组中乘积为正数的最大长度,nums[i]要分正还是负,剩下的子数组都有一个特点就是以 i - 1结尾
  • 所以我们可以将以 i -1 位置元素为结尾的所有子数组中乘积为正数的最大长度拿到
  • 然后在加上nums[i]为正为负的情况。

我们由上面的状态表示去分析,发现当子数组长度大于1,nums[i] < 0,分析不下去了,如果前面 i - 1 位置有乘积为负数最大长度,负数乘nums[i] > 0,乘积也大于0,那长度不也应该加+1嘛。

  • 所以一个状态表示不够。
  • f[i] 表示:以 i 位置元素为结尾所有子数组中乘积为正数的最大长度
  • g[i] 表示:以 i 位置元素为结尾所有子数组中乘积为负数的最大长度
  • 然后再结合上自身的正负,对于F和G的选择进行考虑

2.状态转移方程

我们先来分析一下 f

当长度大于1,nums[i] < 0,所以我们要找到的是 i - 1位置元素为结尾所有子数组中乘积为负数的最大长度,但是要注意的是

  • 万一 g[i - 1] 位置为0呢?也就是说前面根本就没有乘积为负数的最大长度。
  • 所以继续保持为零即可

因此这里不能这样写,需要判断一下:

  • g[i-1]==0?0:g[i-1]+1

再来分析一下g

长度大于1,nums[i] > 0,所以我们要找到的是 i - 1位置元素为结尾所有子数组中乘积为负数的最大长度

  • 但是万一 g[i - 1] 是 0呢?
  • 乘积不可能为负,而nums[i] > 0,这种情况以 i 位置元素为结尾所有子数组中乘积为负数的最大长度就是0,因此下面写的就不对。

正确写法:

  • g[i-1]==0?0:g[i-1]+1

有人可能会有疑问:为什么f 当长度大于1,nums[i] > 0,不去考虑 f[i -1] 为0的情况呢

  • 其实我们已经考虑过了,f[i -1] 为0就为0好了,反正nums[i] > 0至少有1个
  • 同样g 当长度大于1,nums[i] < 0, 不去考虑 f[i -1]为0的情况,都是一样的
  • f[i -1] 为0就为0好了,反正nums[i] < 0至少有1个。如果大于0 就加上好了。

下面可以整体一下状态转移方程

  • f[i],可以把 nums[i] > 0 两种情况合并成 f[i - 1] + 1,因为nums[i] > 0 至少保证有一个了,如果f[i - 1] == 0 最终结果可以是两个1中任何一个
  • 如果 f[i - 1] > 0,最大值是由f[i - 1] + 1来决定,所以不用考虑上面单独1了。
  • nums[i] < 0 两种情况合并成 g[i -1] ==
  • z0 ?:g[i -1] + 1,要么是0,要么是比0更大的数,最大值由g[i -1] == 0 ?:g[i -1]决定
  • 注意因为这个地方求的是长度,长度就只有零和一之分,所以是可以这么合并的

同理g也是这样合并

(维护 g 表其实就是为了对负数做处理,要运用到负负得正)

3.初始化

注意到填表填 0 位置的时候会越界。我们这里可以多申请一个节点

  1. 里面的值要保证后面填表的正确
  2. 下标映射关系

考虑没有填表的时候g第一个位置填什么,nums[0] > 0 填0,nums[0] < 0填1。
代入是不是f[i - 1] 和 g[i -1] 的位置都填0啊,所以虚拟节点填0。

  • 原数组对应的下标要-1

4.填表顺序

  • 从左往右
  • 两个表一起填

5.返回值

  • f表中最大值
class Solution {
public:
    int getMaxLen(vector<int>& nums) 
    {
        int n=nums.size();
        vector<int> f(n+1);
        auto g=f;

        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;
            }
        }
        int ret=0;
        for(int i=1;i<=n;i++)
        {
            ret=max(ret,f[i]);
        }
        return ret; 
    }
};

2.等差数列划分

链接: 413. 等差数列划分

如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。

  • 例如,[1,3,5,7,9][7,7,7,7][3,-1,-5,-9] 都是等差数列。

给你一个整数数组 nums ,返回数组 nums 中所有为等差数组的 子数组 个数。

子数组 是数组中的一个连续序列。

示例 1:

输入:nums = [1,2,3,4]
输出:3
解释:nums 中有三个子等差数组:[1, 2, 3]、[2, 3, 4] 和 [1,2,3,4] 自身。

示例 2:

输入:nums = [1]
输出:0

  • 如果一个数列 至少有三个元素并且任意两个相邻元素之差相同,则称该数列为等差数列。
  • 返回数组 nums 中所有为等差数组的 子数组 个数。

算法原理:

1.状态表示

  • 经验 + 题目要求
  • 以 i 位置为结尾,巴拉巴拉。
    题目要求,求数组中为等差数组的子数组个数,也就是子数组中有多少个等差数列
  • dp[i] 表示:以 i 位置元素为结尾的所有子数组中有多少个等差数列。

2.状态转移方程

  • 如果[a, b, c, d]已经构成一个等差数列,d后面在加一个e,与c、d、e构成等差数列,[a, b, c, d, e]也是构成等差数列。
  • dp[i] 表示:以 i 位置元素为结尾的所有子数组中有多少个等差数列。子数组要求是连续的
  • 所以求 i 位置,要先去看 i -1 和 i - 2 cvs 的位置。
  • i - 2 位置元素设为a,i - 1 位置元素设为b、i 位置元素设为c

先考虑a、b、c是否构成一个等差数列。

  • 如果abc能构成一个等差数列,那就是以ab为结尾的等差数列后面在加一个c,这些数列也是构成一个等差数列,以ab为结尾就相当于以b为结尾,以b为结尾的等差数列,就在dp[i-1]存着。别忘记 abc也能构成一个等差数列。
  • abc不能构成一个等差数列,即使a前面能构成等差数列,但是与 i 位置不连续,因此就构不成以 i 位置为结尾的等差数列

3.初始化

  • 这里我们可以直接把dp[0] = dp[1] = 0
  • 注意重新的下标映射

4.填表顺序

  • 从左往右

5.返回值

  • 注意并不是返回最后一个位置,题目要求找的是所有等差数列的个数,因此我们返回的是dp表所有元素的和
class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& nums) 
    {
        //a b c
        int n=nums.size();
        if(n<2) return 0;
        vector<int> dp(n);
        dp[0]=0,dp[1]=0; //将前两个位置初始为零

        for(int i=2;i<n;i++)
        {
            //下标映射
            int a=nums[i-2],b=nums[i-1],c=nums[i];
            dp[i]=(c-b==b-a?dp[i-1]+1:0); //填表
            //如果可以,那个状态就可以延续过来
        }

        //求和
        int ret=0;
        for(int i=0;i<n;i++)
        {
            ret+=dp[i];
        }
        return ret;
    }
};

3.最长湍流子数组

链接: 978. 最长湍流子数组

给定一个整数数组 arr ,返回 arr最大湍流子数组的长度

如果比较符号在子数组中的每个相邻元素对之间翻转,则该子数组是 湍流子数组

更正式地来说,当 arr 的子数组 A[i], A[i+1], ..., A[j] 满足仅满足下列条件时,我们称其为湍流子数组

  • i <= k < j
    • k 为奇数时, A[k] > A[k+1],且
    • k 为偶数时,A[k] < A[k+1]
  • i <= k < j
    • k 为偶数时,A[k] > A[k+1] ,且
    • k 为奇数时, A[k] < A[k+1]

示例 1:

输入:arr = [9,4,2,10,7,8,8,1,9]
输出:5
解释:arr[1] > arr[2] < arr[3] > arr[4] < arr[5]

示例 2:

输入:arr = [4,8,12,16]
输出:2

  • 给定一个整数数组 arr ,返回 arr 的 最大湍流子数组的长度 。
  • 如果比较符号在子数组中的每个相邻元素对之间翻转,则该子数组是 湍流子数组 。

湍流子数组到底什么东西,我们举个例子,比如说下面,元素大小呈现一升一降的趋势这就是湍流数组。那就称这个数组是湍流子数组。

  • 本身 也算湍流 子数组


算法原理:

1.状态表示

  • 经验 + 题目要求
  • 以 i 位置为结尾,巴拉巴拉

要求找子数组中最大湍流长度。

  • dp[i] 表示:以 i 位置元素为结束的所有子数组中,最大湍流数组的长度

根据最近的一步分析问题,设 i - 1 位置元素为 a,i 位置元素为 b。此时会有三种情况。

  • a > b i位置最后呈现下降趋势
    a < b i位置最后呈现上升趋势
    a == b i位置最呈现平稳趋势

但是我们的状态表示只是表示 以 i 位置元素为结束的所有子数组中,最大湍流数组的长度

并没有分是上升趋势还是下降趋势。

因此一个状态表示不能满足现在的情况。所以我们要换状态表示。

  • f[i] 表示:以 i 位置元素为结尾的所有子数组中,最后呈现 “上升” 状态下的最长湍流数组的长度
  • g[i] 表示:以 i 位置元素为结尾的所有子数组中,最后呈现 “下降” 状态下的最长湍流数组的长度

2.状态转移方程

  • 先来分析f表
    当a > b i 位置最后呈现下降趋势,但是f表要的是 i 位置最后呈现上升趋势,别忘记本身也可以是湍流子数组,因此是1
  • 当a < b i 位置最后呈现上升趋势,去 i - 1位置找到以 i - 1位置为结尾最后呈现下降趋势的最长湍流数组的长度这个就在 g[i - 1]存着,最后别忘记加上1
  • 当 a == b,本身也可以是湍流子数组,因此是1

g表分析和f表分析一样,可以自己试着分析一下。

  • 当a > b i 位置最后呈现下降趋势,去 i - 1位置找到以 i - 1位置为结尾最后呈现上升趋势的最长湍流数组的长度这个就在 f[i - 1]存着,最后别忘记加上1
  • 当a < b i 位置最后呈现上升趋势,但是g表要的是 i 位置最后呈现下降趋势,别忘记本身也可以是湍流子数组,因此是1
  • 当 a == b,本身也可以是湍流子数组,因此是1

3.初始化

填第一个位置会越界,可以把第一个位置初始化,注意本身也可以是湍流子数组,因此第一个位置可以初始化为1

  • 不过这里我们可以把数组初始化都为1,这样的话
    f表 a > b 和 a == b ,g表 a < b 和 a == b
  • 填表的时候就不用考虑了,反正f[i]和g[i]都已经初始化为1了。

4.填表顺序

  • 从左往右
  • 两个表一起填

5.返回值

  • 我们要的是子数组中最大湍流数组的长度,因此是找两个表里面的最大值。
class Solution {
public:
    int maxTurbulenceSize(vector<int>& arr) 
    {
        int n=arr.size();
        vector<int> f(n,1);//本身也是湍流
        auto g=f;
        //统计以各个点为结尾 的 长度

        for(int i=1;i<n;i++)
        {
            int a=arr[i-1],b=arr[i];
            if(a>b)
            {
                f[i]=1;
                g[i]=f[i-1]+1;
            }
            if(a<b)
            {
                f[i]=g[i-1]+1;
                g[i]=1;
            }
        }
        int ret=0;
        for(int i=0;i<n;i++)
        {
            ret=max(ret,max(f[i],g[i]));
        }
        return ret;
    }
};

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

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

相关文章

【图像处理基石】什么是通透感?

一、画面的通透感定义 画面的通透感指图像在色彩鲜明度、空间层次感、物体轮廓清晰度三方面的综合表现&#xff0c;具体表现为&#xff1a; 色彩鲜明&#xff1a;颜色纯净且饱和度适中&#xff0c;无灰暗或浑浊感&#xff1b;层次分明&#xff1a;明暗过渡自然&#xff0c;光…

无锡无人机超视距驾驶证怎么考?

无锡无人机超视距驾驶证怎么考&#xff1f;在近年来&#xff0c;无人机技术的迅猛发展使得无人机的应用场景变得愈发广泛&#xff0c;其不仅在环境监测、农业喷洒、快递配送等领域展现出真金白银的价值&#xff0c;同时也推动了无人机驾驶证的需求。尤其是在无锡&#xff0c;随…

213、【图论】有向图的完全联通(Python)

题目描述 原题链接&#xff1a;105. 有向图的完全联通 代码实现 import collectionsn, k list(map(int, input().split())) adjacency collections.defaultdict(list) for _ in range(k):head, tail list(map(int, input().split()))adjacency[head].append(tail)visited_…

图像形态学操作对比(Opencv)

形态学基于图像的形状进行操作&#xff0c;用于处理二值化图像&#xff0c;主要包括腐蚀和膨胀两种基本操作。这些操作通常用于去除噪声、分隔或连接相邻的元素以及寻找图像中显著的最大点和最小点。 1. 形态学操作 import cv2 import numpy as np import matplotlib.pyplot …

复刻系列-星穹铁道 3.2 版本先行展示页

复刻星穹铁道 3.2 版本先行展示页 0. 视频 手搓&#xff5e;星穹铁道&#xff5e;展示页&#xff5e;&#xff5e;&#xff5e; 1. 基本信息 作者: 啊是特嗷桃系列: 复刻系列官方的网站: 《崩坏&#xff1a;星穹铁道》3.2版本「走过安眠地的花丛」专题展示页现已上线复刻的网…

Linux:进程理解1(查看进程,创造进程,进程状态)

进程理解 &#xff08;一&#xff09;查看进程通过系统调用获取进程标示* &#xff08;二&#xff09;创造进程&#xff08;fork&#xff09;1. 创造的子进程的PCB代码数据怎么来&#xff1f;2.一个函数为什么有两个返回值&#xff1f;3. 为什么这里会有 两个 id值&#xff1f;…

异形遮罩之QML中的 `OpacityMask` 实战

文章目录 &#x1f327;️ 传统实现的问题&#x1f449; 效果图 &#x1f308; 使用 OpacityMask 的理想方案&#x1f449;代码如下&#x1f3af; 最终效果&#xff1a; ✨ 延伸应用&#x1f9e0; 总结 在 UI 设计中&#xff0c;经常希望实现一些“异形区域”拥有统一透明度或颜…

如何为您的设计应用选择高速连接器

电气应用的设计过程需要考虑诸多因素&#xff0c;尤其是在设计高速网络时。许多连接器用户可能没有意识到&#xff0c;除了在两个互连之间组装导电线路之外&#xff0c;还需要考虑各种工艺。在建立高速连接并确保适当的信号完整性时&#xff0c;必须考虑蚀刻、公差、屏蔽等因素…

【论文阅读】UniAD: Planning-oriented Autonomous Driving

一、Introduction 传统的无人驾驶采用了区分子模块的设计&#xff0c;即将无人驾驶拆分为感知规划控制三个模块&#xff0c;这虽然能够让无人驾驶以一个很清晰的结构实现&#xff0c;但是感知的结果在传达到规划部分的时候&#xff0c;会导致部分信息丢失&#xff0c;这势必会…

upload-labs二次打

1(前端js绕过) 弹窗&#xff0c;先看看有没有js有&#xff0c;禁用js 禁用后就可以上传php文件了&#xff0c;然后我们就去访问文件&#xff0c;成功 2&#xff08;MIME绕过&#xff09; 先上传一个php文件试试&#xff0c;不行&#xff0c;.htaccess不行, 试试MIME类型&am…

提权实战!

就是提升权限&#xff0c;当我们拿到一个shell权限较低&#xff0c;当满足MySQL提权的要求时&#xff0c;就可以进行这个提权。 MySQL数据库提权&#xff08;Privilege Escalation&#xff09;是指攻击者通过技术手段&#xff0c;从低权限的数据库用户提升到更高权限&#xff…

ChromeOS 135 版本更新

ChromeOS 135 版本更新 一、ChromeOS 135 更新内容 1. ChromeOS 电池寿命优化策略 为了延长 Chromebook 的使用寿命&#xff0c;ChromeOS 135 引入了一项全新的电池充电限制策略 —— DevicePowerBatteryChargingOptimization&#xff0c;可提供更多充电优化选项&#xff0c…

javaSE.Lambda表达式

如果一个接口中有且只有一个待实现的抽象方法&#xff0c;那么我们可以将匿名内部类简写为Lambda表达式。 简写规则 标准格式&#xff1a; &#xff08;【参数类型 参数名称&#xff0c;】...&#xff09; -> {代码语句&#xff0c; 包括返回值} 只有一行花括号{}可以省略。…

【随身wifi】青龙面板保姆级教程

0.操作前必看 本教程基于Debian系统&#xff0c;从Docker环境。面板安装&#xff0c;到最后拉取脚本的使用。 可以拉库跑狗东京豆&#xff0c;elm红包等等&#xff0c;也可以跑写自己写的脚本&#xff0c;自行探索 重要的号别搞&#xff0c;容易黑号&#xff0c;黑号自己负责…

Android 之美国关税问题导致 GitHub 403 无法正常访问,责任在谁?

这几天各国关税问题导致世界动荡不安&#xff0c;如今GitHub又无法正常访问&#xff0c;是不是Google到时候也无法正常使用了。

4月13日星期日早报简报微语报早读

4月13日星期日&#xff0c;农历三月十六&#xff0c;早报#微语早读。 1、北京处置倒伏树木843棵&#xff0c;已全部处置完毕&#xff1b; 2、山西大同“订婚强奸案”本月16日二审宣判&#xff0c;一审男方被判3年刑&#xff1b; 3、今年我国快递业务量已突破500亿件&#xf…

动态路由, RIP路由协议,RIPv1,RIPv2

动态路由 1、回顾 路由&#xff1a;从源主机到目标主机的过程 源主机发送数据给目标主机&#xff0c;源主机会查看自身的路由信息 如果目标主机是自己同网段&#xff0c;源主机查看的是直连路由 如果目标主机和自己不同网段&#xff0c;源主机查看的是静态路由、动态路由、默…

【已更新完毕】2025泰迪杯数据挖掘竞赛B题数学建模思路代码文章教学:基于穿戴装备的身体活动监测

基于穿戴装备的身体活动监测 摘要 本研究基于加速度计采集的活动数据&#xff0c;旨在分析和统计100名志愿者在不同身体活动类别下的时长分布。通过对加速度数据的处理&#xff0c;活动被划分为睡眠、静态活动、低强度、中等强度和高强度五类&#xff0c;进而计算每个志愿者在…

212、【图论】字符串接龙(Python)

题目描述 题目链接&#xff1a;110. 字符串接龙 代码实现 import collectionsn int(input()) beginStr, endStr input().split() strList [input() for _ in range(n)]deque collections.deque() # 使用队列遍历结点 deque.append([beginStr, 1]) # 存储当前字符串和遍…

【UE5】RTS游戏的框选功能+行军线效果实现

目录 效果 步骤 一、项目准备 二、框选NPC并移动到指定地点 三、框选效果 四、行军线效果 效果 步骤 一、项目准备 1. 新建一个俯视角游戏工程 2. 新建一个pawn、玩家控制器和游戏模式,这里分别命名为“MyPawn”、“MyController”和“MyGameMode” 3. 打开“MyGam…