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
的最大湍流子数组的长度。
解法:动态规划
解题思路: 这道题要我们找到一个子数组,该子数组所有两个相邻的数据是一大一小的,因此我们可以用一个一维的dp数组,该数组的含义是,以它为最后的一个数字的端流子数组的长度,因此我们可以得到一个动态转移方程
dp[i] = dp[i-1]+1,当A[i]跟前面A[i-1]能够形成端流子数组时
dp[i] = 2, 如果跟前面的无法形成端流子数组,但是跟前面的值不相等,那就跟前面一个数重新组成端流子数组
dp[i] = 1, 如果A[i]跟前面的值相同,那这时候要跟前面组成端流子数组也没办法了,因此dp[i]只能等于1
我们看一下代码实现部分,首先我们需要定义一个flag标志数字,flag的含义为A[i]应该小于A[i-1] (当flag=0)还是大于A[i-1] (当flag=1),当A[i-1] == A[i-2] 时,我们将flag置为-1,表示我们不知道应该将flag置为多少,让A[i]跟A[i-1]比较后重新判断
首先初始化
dp[0] = 1; //首先,第一个数字满足端流子数组,所以初始化为1
if(A[1]>A[0])
//如果A[1]大于A[0],那A[2]应该小于A[1],所以我们将flag置为0,0表示小于
{
flag=0;
dp[1]=2;
}
else if(A[1]<A[0])同理,flag=1表示大于
{
flag=1;
dp[1]=2;
}
else
//如果A[0]==A[1],那这两个数字没办法构成端流子数组,所以flag置为-1,-1表示A[2]得重新判断应该将flag置为多少
{
flag=-1;
dp[1]=1;
}
循环结构的代码
for(int i=2; i<A.length; i++)
//从数字第二个位置开始遍历
{
if(flag==1)
//如果flag==1,表示A[i]应该大于A[i-1]
{
if(A[i]>A[i-1])
//如果满足,那么这个端流子数组可以直接扩展一个长度
{
dp[i] = dp[i-1]+1;
flag = 0;//将flag置为0,表示A[i+1]应该小于A[i]
}
else if(A[i]<A[i-1])
//如果不满足,那就舍弃前面积累的端流子数组长度,直接以A[i]和A[i-1]组成一个新的端流子数组,这时候flag不用改变,因为A[i]和A[i-1]不满足flag,下一个应该满足
dp[i] = 2;
else
//如果A[i-1]和A[i]相等,这时候我们没办法组成一个新的端流子数组,所以dp[i]=1,同时不知道下一个数应该是大于dp[i]还是小于dp[i],所以将flag置为-1,要进行类似于初始化时的动作
{
dp[i] = 1;
flag = -1;
}
}
else if(flag==0)
//道理同上
{
if(A[i]<A[i-1])
{
dp[i] = dp[i-1]+1;
flag = 1;
}
else if(A[i]>A[i-1])
dp[i] = 2;
else
{
dp[i] = 1;
flag = -1;
}
}
else // flag=-1,重新判断flag
{
if(A[i]<A[i-1])
{
dp[i] = dp[i-1]+1;
flag = 1;
}
else if(A[i]>A[i-1])
{
dp[i] = dp[i-1]+1;
flag = 0;
}
else
{
dp[i] = 1;
flag = -1;
}
//这里的操作跟初始时一模一样
}
max = Math.max(max, dp[i]);
}
结果
心得体会
这次是唯一一次自己做出来的,之前做了十几道题,总是想不出来,都快怀疑自己做题有没有用了,这次是一次提交一次过,算是有进步了^_^
题目来源于
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-turbulent-subarray
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。