【面试经典】颠簸的波浪——摆动数组问题的标准答案

引入定义

如果连续数字之间的差严格地在正数和负数之间交替,称为摆动数组。

举几个例子。[1,7,4,9,2,5]是一个典型的摆动数组,它就像颠簸的波浪;[1,7,4,5,5]不是摆动数组,因为它不是严格的上下摆动;[1][1,5]都符合定义,是摆动数组。

 
 

题目两则

Q1. 返回数组所包含的最大连续摆动数组的长度。
 
输入:[9,4,2,10,7,8,8,1,9]
输出:5
解释:[4,2,10,7,8]长度为2

Q2. 返回数组所包含的最大摆动数组的长度,不要求连续。
 
输入:[1,17,5,10,13,15,10,5,16,8]
输出:7
解释:[1,17,10,13,10,16,8]长度为7

 
 

答案两则

  1. 摆动数组的答案比较模板化———用两个变量记录此时摆动数组的长度情况(up, down)
  2. up的意义是,遍历到该处时,假设摆动数组正处于上升状态,它的长度;down的意义是,遍历到该处时,假设摆动数组正处于下降状态,它的长度
  3. 必须要理解的是,这两个摆动数组并不是同一个,因为我们假设了其结尾分别处于上升/下降状态
  4. 关键还在于这两个状态的转换,即up和down交叉转换(联系股票问题)
  5. 因为Q1要求连续,因此当摆动数组断裂时,up/down要重置为1;而Q2不要求连续,即摆动数组隐藏在整个数组中,up/down不需要重置,只需要继承(关键区别)
class Solution {
    
    
    public int maxTurbulenceSize(int[] arr) {
    
    
        int up = 1;
        int down = 1;
        int res = 1;
        
        for(int i = 1; i < arr.length; 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;
    }
}
class Solution {
    
    
    public int maxTurbulenceSize(int[] arr) {
    
    
        int up = 1;
        int down = 1;

        for(int i = 1; i < arr.length; i++) {
    
    
            if(arr[i] > arr[i - 1]) {
    
    
                up = down + 1;
            }
            if(arr[i] < arr[i - 1]) {
    
    
                down = up + 1;
            }
        }
        return Math.max(up, down);
    }
}

 
 

思考探究

等一下,这种状态的交叉转化,让我们想到了经典的股票问题(戳这里),因此所谓的up/down模板,会不会就是动态规划经过滚动数组优化的结果

是的。
 
下面我们从动态规划的角度,来还原出这道题完整的思路演化过程。

dp[i][0]的含义是,以i处为结尾的且结尾处于上升状态的摆动数组的最大长度

dp[i][1]的含义是,以i处为结尾的且结尾处于下降状态的摆动数组的最大长度

// 状态转移
if(arr[i] > arr[i - 1]) {
    
    
	dp[i][0] = dp[i][1] + 1;
}
if(arr[i] < arr[i - 1]) {
    
    
	dp[i][1] = dp[i][0] + 1;
}

// 滚动优化
if(arr[i] > arr[i - 1]) {
    
    
	dp[0] = dp[1] + 1;
}
if(arr[i] < arr[i - 1]) {
    
    
	dp[1] = dp[0] + 1;
}

 
 

一点理解

  动态规划中,定义出dp[i][0/1]的含义是关键点也是难点。记住一件事,dp[i]的含义是“此时/此地完成了i的变化后,所处状态(0/1)所对应的值”,关键在于“状态”;

  在股票问题中,dp[i][0/1]的含义倾向于状态(持股/不持股)而非动作(买入/卖出);在摆动数组中,dp[i][0/1]的含义也是倾向于状态(上升下降的状态)而非动作(上升下降的动作)———理解状态二字,至关重要。

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

E N D END END

猜你喜欢

转载自blog.csdn.net/m0_46202073/article/details/113763799