title: 最长xx数组
tags:

  • 算法
  • java
    categories: 计算机
    declare: true
    mathjax: true
    copyright: true
    abbrlink: 1122acc
    date: 2021-02-08 11:22:14

最长xx数组

一、最长湍流子数组

本篇文章是对Leetcode第978题[最长湍流子数组]的总结:

1. 题目描述:

当 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:

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

示例 2:

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

示例 3:

输入:[100]
输出:1

2. 解决方案:

1、双指针

在这种方法中,需要注意的是:

  1. left==right时,需要考虑下一个数,若相等,则跳过;
  2. 当不满足湍流条件时,left应该直接跳到right部分,因为其中一段不满足,整个子数组必然不满足;
  3. 计算长度时,需要长度加1,即right - left +1
public int maxTurbulenceSize(int[] arr) {
        int n = arr.length;
        int res = 1;
        int left = 0 , right = 0;

        while(right < n-1 ){
            if(left == right ){
                if(arr[left] == arr[left+1]){
                    left ++;
                }
                right++;
            }
            else{
                if(arr[right-1] > arr[right] && arr[right] < arr[right+1]){
                    right++;
                }else if(arr[right-1] < arr[right] && arr[right] > arr[right+1]){
                    right ++;
                }else{
                    left = right;
                }
            }
            res = Math.max(res,right-left+1);
        }
        return res;
    }

2、动态规划

动态规划首先需要我们定义状态是什么,然后根据题意,写出状态转移方程。

对于==最长连续子数组==问题,使用动态规划求解时,我们经常定义状态 dp[i] 为:以 i 位置结尾的最长连续子数组的长度,因为这个状态可以反映 i 位置及其前面区间的情况。下一个位置 i + 1 可以根据 dp[i] 就知道了前面的情况,再根据 arr[i + 1] 和 arr[i] 的大小关系,能更新状态 dp[i + 1]。

对于本题,如果只定一个状态数组是不够的,因为我们只有区分了 i 位置是在增长还是在降低,才能判断 i + 1 位置是否能续上前面的波浪。所以,我们需要定义两个状态数组,分别表示以 i 结尾的在增长和降低的最长湍流子数组长度。

状态的定义:

定义 up[i] 表示以位置 i 结尾的,并且 arr[i - 1] < arr[i] 的最长湍流子数组长度。
定义 down[i] 表示以位置 i 结尾的,并且 arr[i - 1] > arr[i] 的最长湍流子数组长度。
up[i] 和 down[i] 初始化都是 1,因为每个数字本身都是一个最小的湍流子数组。

public int solutionByDp(int[] arr){
        int n = arr.length;
        int up = 1, down = 1; //dp数组
        int res = 1;
        for (int i = 1; i < n ; i++){
            if (arr[i] > arr[i-1]){
                up = down + 1;
                down = 1;
            }else if (arr[i] < arr[i-1]){
                down = up +1;
                up = 1;
            }else {
                up = 1;
                down = 1;
            }
            res = Math.max(res,Math.max(up,down));
        }
        return res;
    }