「动态规划」如何求最长湍流子数组的长度?

2024-06-22 18:52

本文主要是介绍「动态规划」如何求最长湍流子数组的长度?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

78. 最长湍流子数组icon-default.png?t=N7T8https://leetcode.cn/problems/longest-turbulent-subarray/description/

给定一个整数数组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。
  3. 输入:arr = [100],输出:1。

提示:1 <= arr.length <= 4 * 10^4,0 <= arr[i] <= 10^9。


我们用动态规划的思想来解决这个问题。

确定状态表示:根据经验和题目要求,我们用dp[i]表示:以i位置为结尾的所有子数组中,最长湍流子数组的长度。但是这样的状态表示推不出状态转移方程,所以我们需要更细的划分:

  • 用f[i]表示:以i位置为结尾的所有最后呈现上升趋势的子数组中,最长湍流子数组的长度
  • 用g[i]表示:以i位置为结尾的所有最后呈现下降趋势的子数组中,最长湍流子数组的长度

推导状态转移方程:考虑最近的一步。以i位置为结尾的湍流子数组和以i - 1位置为结尾的湍流子数组有什么关系呢?以f[i]为例,分类讨论:

  • 如果arr[i - 1] >= arr[i],那么以i位置为结尾的最后呈现上升趋势的最长湍流子数组就是arr[i]本身,即f[i] = 1。
  • 如果arr[i - 1] < arr[i],那么以i位置为结尾的最后呈现上升趋势的最长湍流子数组,就应该是「以i - 1位置为结尾的最后呈现下降趋势的最长湍流子数组」的末尾添加arr[i]之后,形成的湍流子数组,即f[i] = g[i - 1] + 1。

综上所述:f[i] = arr[i - 1] >= arr[i] ? 1 : g[i - 1] + 1。同理,g[i] = arr[i - 1] <= arr[i] ? 1 : f[i - 1] + 1。换句话说,f[i]和g[i]默认是1,如果arr[i - 1] < arr[i],那么f[i] = g[i - 1] + 1;如果arr[i - 1] > arr[i],那么g[i] = f[i - 1] + 1

初始化:根据状态转移方程,我们需要初始化f[0]和g[0]的值,防止越界。显然f[0] = g[0] = 1

填表顺序:根据状态转移方程,显然应从左往右,同时填两个表

返回值:根据状态表示,由于我们不确定最长湍流子数组的结束位置,所以应返回f表和g表中,所有元素的最大值

细节问题:显然f表和g表的规模和arr相同,均为1 x n

时间复杂度:O(N),空间复杂度:O(N)。

class Solution {
public:int maxTurbulenceSize(vector<int>& arr) {int n = arr.size();// 创建dp表vector<int> f(n, 1);auto g = f;// 填表for (int i = 1; i < n; i++) {if (arr[i - 1] < arr[i]) {f[i] = g[i - 1] + 1;} else if (arr[i - 1] > arr[i]) {g[i] = f[i - 1] + 1;}}// 返回结果return max(*max_element(f.begin(), f.end()),*max_element(g.begin(), g.end()));}
};

这篇关于「动态规划」如何求最长湍流子数组的长度?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1085125

相关文章

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

MySQL中动态生成SQL语句去掉所有字段的空格的操作方法

《MySQL中动态生成SQL语句去掉所有字段的空格的操作方法》在数据库管理过程中,我们常常会遇到需要对表中字段进行清洗和整理的情况,本文将详细介绍如何在MySQL中动态生成SQL语句来去掉所有字段的空... 目录在mysql中动态生成SQL语句去掉所有字段的空格准备工作原理分析动态生成SQL语句在MySQL

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C#如何动态创建Label,及动态label事件

《C#如何动态创建Label,及动态label事件》:本文主要介绍C#如何动态创建Label,及动态label事件,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#如何动态创建Label,及动态label事件第一点:switch中的生成我们的label事件接着,

SpringCloud动态配置注解@RefreshScope与@Component的深度解析

《SpringCloud动态配置注解@RefreshScope与@Component的深度解析》在现代微服务架构中,动态配置管理是一个关键需求,本文将为大家介绍SpringCloud中相关的注解@Re... 目录引言1. @RefreshScope 的作用与原理1.1 什么是 @RefreshScope1.

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

mybatis-plus 实现查询表名动态修改的示例代码

《mybatis-plus实现查询表名动态修改的示例代码》通过MyBatis-Plus实现表名的动态替换,根据配置或入参选择不同的表,本文主要介绍了mybatis-plus实现查询表名动态修改的示... 目录实现数据库初始化依赖包配置读取类设置 myBATis-plus 插件测试通过 mybatis-plu

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.