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.
Examples:
Input: [1,7,4,9,2,5] Output: 6 The entire sequence is a wiggle sequence. Input: [1,17,5,10,13,15,10,5,16,8] Output: 7 There are several subsequences that achieve this length. One is [1,17,10,13,10,16,8]. Input: [1,2,3,4,5,6,7,8,9] Output: 2
Follow up:
Can you do it in O(n) time?
方法1:
先来DP法,对于从index=0到当前位置index=i这段,用dp[i]表示最大的wiggle sequence长度,这个长度肯定是由前面某个位置+1得到的,而前面某个位置对应的差值数组中的元素可能为正,也可能为负,所以需要两组dp来记录,分别表示当前差值为正和当前差值为负所能取到的最大长度。
举例1,序列[1,17,5,10,13,15,10,5,16,8]对应的dp序列
1 | 17 | 5 | 10 | 13 | 15 | 10 | 5 | 16 | 8 | |
+ | 1 | 2 | 2 | 4 | 4 | 4 | 4 | 2 | 6 | 6 |
- | 1 | 1 | 3 | 3 | 3 | 3 | 5 | 5 | 3 | 7 |
举例2,序列[1,8,7,5,6,4,5,6,9]对应的DP序列
1 | 8 | 7 | 5 | 6 | 4 | 5 | 6 | 9 | |
+ | 1 | 2 | 2 | 2 | 4 | 2 | 6 | 6 | 6 |
- | 1 | 1 | 3 | 3 | 3 | 5 | 5 | 3 | 1 |
状态转移方程
dp[i][0]=max{dp[j][1]}+1 当nums[i]>nums[j]
dp[i][1]=max{dp[j][0]}+1 当nums[i]<nums[j]
其中 0<=j<i
复杂度O(N^2)
public class Solution {
public static int wiggleMaxLength(int[] nums)
{
int len=nums.length;
if(len<=1)
return len;
int[][] dp=new int[len][2];
dp[0][0]=1;
dp[0][1]=1;
for(int i=1;i<len;i++)
{
int a=Integer.MIN_VALUE;
int b=Integer.MIN_VALUE;
for(int k=i-1;k>=0;k--)
{
if(nums[i]>nums[k])
a=Math.max(a, dp[k][1]);
else if(nums[i]<nums[k])
b=Math.max(b, dp[k][0]);
}
dp[i][0]=(a>Integer.MIN_VALUE?a+1:1);
dp[i][1]=(b>Integer.MIN_VALUE?b+1:1);
}
return Math.max(dp[len-1][0], dp[len-1][1]);
}
}
--------------------------------------------------------------------------------
方法2,贪心
从序列的长度对应关系可以看出
[1,17,5,10,13,15,10,5,16,8]对应的wiggle sequence长度是
[1, 2, 3, 4, 4, 3, 5, 5, 6, 6],可以发现连续的升序或者降序(局部升序或者降序>=3个元素),长度不再增加,按照这个思路,可以得到一个
O(N)的贪心策略解法
代码来自https://discuss.leetcode.com/topic/51811/java-o-n-greedy-solution
public class Solution {
public int wiggleMaxLength(int[] nums) {
if(nums.length <= 1) return nums.length;
int count = 1;
Boolean prevInc = null;
for(int i = 1; i < nums.length; i++) {
if(nums[i] > nums[i - 1] && (prevInc == null || !prevInc)) {
prevInc = true;
count++;
} else if(nums[i] < nums[i - 1] && (prevInc == null || prevInc)) {
prevInc = false;
count++;
}
}
return count;
}
}