问题描述
A sequence of numbers is called a wiggle sequence if the differences between successive numbers strictly alternate between positive and negative. The first difference (if one exists) may be either positive or negative. A sequence with fewer than two elements is trivially a wiggle sequence.
For example, [1,7,4,9,2,5]
is a wiggle sequence because the differences (6,-3,5,-7,3)
are alternately positive and negative. In contrast, [1,4,7,2,5]
and [1,7,4,5,5]
are not wiggle sequences, the first because its first two differences are positive and the second because its last difference is zero.
Given a sequence of integers, return the length of the longest subsequence that is a wiggle sequence. A subsequence is obtained by deleting some number of elements (eventually, also zero) from the original sequence, leaving the remaining elements in their original order.
Example 1:
Input: [1,7,4,9,2,5]
Output: 6
Explanation: The entire sequence is a wiggle sequence.
分析
这道题我很快有了自己的思路:计算nums[i]-nums[i-1]的差dif[i-1],并判断dif[i-1]和dif[i-2]是否是异号(相乘是否小于0)。
但是这个思路对于相邻数相等的情况非常不友好。我一开始修改的是if(dif[i-1]*dif[i-2]<0||(dif[i-2]==0&&dif[i-1])),即增加一种情况,如果该数之前的两个相等且dif[i-1]非0时,当前数也可以保留。但这样的解法不对,举一个例子:1,2,2,2,2,4.所以dif[i-1]还要参考前面最接近的非零的dif[*]的正负。当然要注意的是,很有可能前面所有的差值都是0.
所以步骤如下:
先判断前一个差值dif[i-2]是否为0
如果为0:如果前面差值都是0,且dif[i-1]不为0,或者dif[i-1]和前面最接近的非零的dif[*]异号,长度加1
如果不为0:就直接判断dif[i-1]和dif[i-2]是否是异号即可。
注意:代码中我用了dp数组,还可以更优化,将其只用一个变量代替,因为它只有两种可能:不变,或者+1.
代码(不够简洁)
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
int len=nums.size();
if(len==1)
return 1;
if(len<=0)
return 0;
int flag=0;
int dp[len];
int dif[len-1];
dp[0]=1;
dif[0]=nums[1]-nums[0];
if(dif[0]!=0)
dp[1]=2;
else dp[1]=1;
for(int i=2;i<len;i++)
{
dif[i-1]=nums[i]-nums[i-1];
if(dif[i-2]==0)
if((flag==0&&dif[i-1]!=0)||(flag!=0&&(flag*dif[i-1]<0)))
dp[i]=dp[i-1]+1;
else dp[i]=dp[i-1];
else if(dif[i-1]*dif[i-2]<0)
dp[i]=dp[i-1]+1;
else
dp[i]=dp[i-1];
if (dif[i-1]!=0)
flag=dif[i-1];
}
return dp[len-1];
}
};
别人更巧妙的思路:
用up和down两个变量来统计。
如果dif[i-1]<0,说明它是一个下降的趋势,down=up+1;
如果dif[i-1]>0,说明它是一个上升的趋势,up=down+1;
这样交叉的统计非常巧妙。1,4,5,6,up和down初始化为1,
对于1,4,up=down+1=2;
对于4,5,down=up+1=3;
对于5,6,down=up+1=3;