问题来源:leetcode 978。

最长湍流子数组

A 的子数组 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]
    也就是说,如果比较符号在子数组中的每个相邻元素对之间翻转,则该子数组是湍流子数组。

返回 A 的最大湍流子数组的长度。

示例 1:

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

示例 2:

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

示例 3:

输入:[100]
输出:1

提示:

  • 1 <= A.length <= 40000
  • 0 <= A[i] <= 10^9

动态规划

优化子结构设以 arr[i]arr[i]arr[i] 为结尾的最长湍流子数组的长度为 nnn,证明该问题的最优解包含其子问题的最优解,或者说该问题的最优解可以由其子问题的最优解构造得到:

  • 如果 arr[i]==arr[i−1]arr[i] == arr[i-1]arr[i]==arr[i−1],那么以 arr[i]arr[i]arr[i] 为结尾的最长湍流子数组的长度为 111,不需要子问题的解。
  • 如果 arr[i]>arr[i−1]arr[i] > arr[i-1]arr[i]>arr[i−1] 且 arr[i−1]<arr[i−2]arr[i-1] < arr[i-2]arr[i−1]<arr[i−2],那么 n−1n-1n−1 是子问题(以 arr[i−1]arr[i-1]arr[i−1] 为结尾的数组)的最长湍流子数组的长度,也就是说只需要求解该子问题。可以通过反证法证明:假设子问题的最长湍流子数组的长度大于 n−1n-1n−1,那么又因为 arr[i]>arr[i−1]arr[i] > arr[i-1]arr[i]>arr[i−1] 且 arr[i−1]<arr[i−2]arr[i-1] < arr[i-2]arr[i−1]<arr[i−2],所以 arr[i]arr[i]arr[i] 可以接在该湍流子数组的后面,所以以 arr[i]arr[i]arr[i] 为结尾的最长湍流子数组的长度就大于 nnn,与假设矛盾。
  • 如果 arr[i]<arr[i−1]arr[i] < arr[i-1]arr[i]<arr[i−1] 且 arr[i−1]>arr[i−2]arr[i-1] > arr[i-2]arr[i−1]>arr[i−2],那么 n−1n-1n−1 是子问题(以 arr[i−1]arr[i-1]arr[i−1] 为结尾的数组)的最长湍流子数组的长度,证明过程与前面相同。
  • 对于其他情况(arr[i]>arr[i−1]>arr[i−2]arr[i] > arr[i-1] > arr[i-2]arr[i]>arr[i−1]>arr[i−2] 或 arr[i]<arr[i−1]<arr[i−2]arr[i] < arr[i-1] <arr[i-2]arr[i]<arr[i−1]<arr[i−2]),那么无论以 arr[i−1]arr[i-1]arr[i−1] 为结尾的最长湍流子数组的长度为多少,以 arr[i]arr[i]arr[i] 结尾的最长湍流子数组的长度为 2。
  • 还有 arr[i−2]arr[i-2]arr[i−2] 不存在的情况,只需要看 arr[i]arr[i]arr[i] 与 arr[i]arr[i]arr[i] 是否相等,就可以得到原问题的解。

重叠子问题:简单地使用递归算法来求解,很容易发现具有子问题被重复计算。

递归地定义最优解的值设 dp[i]dp[i]dp[i] 表示以 arr[i]arr[i]arr[i] 结尾的最长湍流子数组的长度,对于数组的每个位置 iii,以该位置元素结尾的最长湍流子数组的长度计算过程如下:

  • 首先初始化 dpdpdp 数组的所有位置都为 111。
  • 如果 dp[i−1]dp[i-1]dp[i−1] 为 1:
    • 如果 arr[i]≠arr[i−1]arr[i] \neq arr[i-1]arr[i]​=arr[i−1] 时,dp[i]=2dp[i]=2dp[i]=2;
    • 否则保持 111 不变。
  • 否则:
    • 如果 arr[i]>arr[i−1]arr[i] > arr[i-1]arr[i]>arr[i−1] 且 arr[i−1]<arr[i−2]arr[i-1] < arr[i-2]arr[i−1]<arr[i−2] 或 arr[i]<arr[i−1]arr[i] < arr[i-1]arr[i]<arr[i−1] 且 arr[i−1]>arr[i−2]arr[i-1] > arr[i-2]arr[i−1]>arr[i−2],那么 dp[i]=dp[i−1]+1dp[i] = dp[i-1] + 1dp[i]=dp[i−1]+1;
    • 否则看 arr[i−1]arr[i-1]arr[i−1] 与 arr[i]arr[i]arr[i] 是否相等,不相等的话将 dp[i]dp[i]dp[i] 的值置为 222。

自底向上地计算最优解的值:只需要从前向后遍历数组,便可以确保每一个问题计算时,其相关的子问题均已经被计算了出来。

class Solution {public:int maxTurbulenceSize(vector<int>& arr) {int n = arr.size();if(n == 1) {return 1;}vector<int> dp(n, 1);for(int i = 1; i<n; i++) {if(dp[i-1] == 1) {dp[i] = arr[i-1] == arr[i] ? 1 : 2;} else if(arr[i] != arr[i-1]) {if((arr[i] > arr[i-1] && arr[i-1] < arr[i-2]) || (arr[i] < arr[i-1] && arr[i-1] > arr[i-2])) {dp[i] = dp[i-1] + 1;} else {dp[i] = 2;}}}return *max_element(dp.begin(), dp.end());}
};

空间优化:注意到每个 dp[i]dp[i]dp[i] 只与 dp[i−1]dp[i-1]dp[i−1] 相关,所以可以通过一个变量来表示 dpdpdp 数组,另外再通过一个变量保存当前最长湍流子数组的长度即可。

class Solution {public:int maxTurbulenceSize(vector<int>& arr) {int n = arr.size();if(n == 1) {return 1;}int result = 1, temp = 1;for(int i = 1; i<n; i++) {if(temp == 1) {temp = arr[i-1] == arr[i] ? 1 : 2;} else if(arr[i] != arr[i-1]) {if((arr[i] > arr[i-1] && arr[i-1] < arr[i-2]) || (arr[i] < arr[i-1] && arr[i-1] > arr[i-2])) {temp++;} else {temp = 2;}}result = temp > result ? temp : result;}return result;}
};

动态规划——最长湍流子数组相关推荐

  1. LeetCode——978. 最长湍流子数组(Longest Turbulent Subarray)——分析及代码(Java)

    LeetCode--978. 最长湍流子数组[Longest Turbulent Subarray]--分析及代码[Java] 一.题目 二.分析及代码 1. 动态规划(一维数组) (1)思路 (2) ...

  2. 2021年2月8日 Leetcode每日一题:978. 最长湍流子数组

    最长湍流子数组 1.题目描述 当 A 的子数组 A[i], A[i+1], -, A[j] 满足下列条件时,我们称其为湍流子数组: 若 i <= k < j,当 k 为奇数时, A[k] ...

  3. 算法---最长湍流子数组

    题目 最长湍流子数组当 A 的子数组 A[i], A[i+1], ..., A[j] 满足下列条件时,我们称其为湍流子数组:若 i <= k < j,当 k 为奇数时, A[k] > ...

  4. LeetCode-978:最长湍流子数组

    题目描述: 当 A 的子数组 A[i], A[i+1], ..., A[j] 满足下列条件时,我们称其为湍流子数组: 若 i <= k < j,当 k 为奇数时, A[k] > A[ ...

  5. 湍流参数计算c语言,力扣978.最长湍流子数组-C语言

    题目 最长湍流子数组 当 A 的子数组 A[i], A[i+1], ..., A[j] 知足下列条件时,咱们称其为湍流子数组:算法 若 i <= k < j,当 k 为奇数时, A[k] ...

  6. Leetcode 978. 最长湍流子数组

    978. 最长湍流子数组 显示英文描述 我的提交返回竞赛 用户通过次数196 用户尝试次数229 通过次数200 提交次数567 题目难度Medium 当 A 的子数组 A[i], A[i+1], . ...

  7. LeetCode 978. 最长湍流子数组(DP)

    1. 题目 当 A 的子数组 A[i], A[i+1], ..., A[j] 满足下列条件时,我们称其为湍流子数组: 若 i <= k < j,当 k 为奇数时, A[k] > A[ ...

  8. C++描述 LeetCode 978. 最长湍流子数组

    C++描述 LeetCode 978. 最长湍流子数组   大家好,我叫亓官劼(qí guān jié ),在CSDN中记录学习的点滴历程,时光荏苒,未来可期,加油~博主目前仅在CSDN中写博客,唯一 ...

  9. LeetCode 978 最长湍流子数组

    LeetCode 978 最长湍流子数组 题目链接 当 A 的子数组 A[i], A[i+1], -, A[j] 满足下列条件时,我们称其为湍流子数组: 若 i <= k < j,当 k ...

最新文章

  1. linux中创建本地yum库,轻松安装Linux软件
  2. ubuntu和windows实现互相之间远程控制
  3. oracle查询表的索引
  4. [译]管理IIS日志的存储
  5. Dapr微服务应用开发系列3:服务调用构件块
  6. (1)解锁MongoDB replica set核心姿势
  7. 【框架篇】mvc、mvp、mvvm使用关系总结
  8. csdn的blog后台程序的导航菜单的实现
  9. 学习日报 1028 分支结构 if分支语句
  10. linux中的管道和重定向
  11. 字符设备驱动(四)按键中断
  12. 使用 LaTeX 语言对 MATLAB 中的图片进行标注
  13. Windows平台上使用Qt(MinGW)调用基于VS编写的周立功CAN卡Dll文件
  14. Python中jieba库的使用
  15. IOS客户端接入FaceB,SSO授权
  16. 计算机主板尺寸,电脑主板大中小三个等级的尺寸是多少?
  17. python结巴怎么安装pip_Python3.6 结巴分词安装和使用
  18. 前端js华为云obs上传下载文件与进度条的设置
  19. python双下划线什么意思_python中_、__、__xx__(单下划线、双下划线等)的含义
  20. linux unix 可视化界面,Linux/UNIX远程调用图形化界面的一种方法

热门文章

  1. 基于Lucene的中文文本分词
  2. 【读后感】读《了不起的盖茨比》后感
  3. 深度学习入门笔记(六):浅层神经网络
  4. Spring5框架-IOC容器
  5. java跟踪行为分析_PiggyMetrics
  6. 第三方开源库:轮播图:Banner/Kanner
  7. 数据挖掘分析考试笔记
  8. java格式化时间字符串 毫秒_SimpleDateFormat是否有格式字符串来获取毫秒日期时间值,而不是人类可读的格式?...
  9. PCB抄板原理图常见错误
  10. 单系统 台电x80pro_转载:台电X80 Pro Plus 刷Windows10单系统