376.Wiggle Subsequence 解题报告
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?
因为题目要求用O(n) time,所以这里我选择了贪心算法。
它的原理是:如果连续3个数都是升序或者降序的话(1,2,3 或者 3,2,1),那么它的wiggle subsequence 就不会增加。
代码如下:
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
//greedy
if (nums.size() < 2) return nums.size();
int i = 1;
int count = 1;
while (i < nums.size() && nums[i] == nums[i - 1]) i++;
bool diff = nums[i] > nums[i - 1];
for (; i < nums.size(); i++) {
if (diff)
while (i + 1 < nums.size() && nums[i] <= nums[i + 1]) i++;
else
while(i + 1 < nums.size() && nums[i] >= nums[i + 1]) i++;
diff = !diff;
count += 1;
}
return count;
}
};
还有一种方法是用DP:这个方法的时间复杂度是O(n^2)
状态转移方程
dp[i][0]=max{dp[j][1]}+1 当nums[i]>nums[j]
dp[i][1]=max{dp[j][0]}+1 当nums[i]
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]);
}
}