题目:
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?
分析:一个数组,如果数组中后一个元素减去前一个元素的值组成的新数组有这样的特点:正负交替,那么这个序列就是一个wiggle序列。给出一个数组,要求求出其中满足wiggle序列的最大子数组。这道题自己没想出来,针对网上的答案,大概可以有两种方法:
第一种:动态规划算法
对于数组中的任意一个元素,这里只有可能有三种状态:
(1)升序,即nums[i]-nums[i-1]>0
(2)降序,即nums[i]-nums[i-1]<0
(3)无变化,即nums[i]=nums[i-1]
所以,我们这里可以使用两个数组一个up[]和down[]数组记录到当前点 i 的最大的wiggle序列的长度。
(1)如果nums[i]>nums[i-1],说明是wiggle序列的升序,它的前一个元素肯定是一个down元素,所以up[i] = down[i-1] + 1,down[i]的值不变和前一个相同
(2)如果nums[i]<nums[i-1],说明是wiggle序列的降序,它的前一个元素肯定是一个up元素,所以 down[i] = up[i-1] + 1,up[i]的值不变和前一个相同
(3)如果nums[i]=nums[i-1],up和down的值都不变
代码:
public class Solution { public int wiggleMaxLength(int[] nums) { if( nums.length == 0 ) return 0; int[] up = new int[nums.length]; int[] down = new int[nums.length]; up[0] = 1; down[0] = 1; for(int i = 1 ; i < nums.length; i++){ if( nums[i] > nums[i-1] ){ up[i] = down[i-1]+1; down[i] = down[i-1]; }else if( nums[i] < nums[i-1]){ down[i] = up[i-1]+1; up[i] = up[i-1]; }else{ down[i] = down[i-1]; up[i] = up[i-1]; } } return Math.max(down[nums.length-1],up[nums.length-1]); } }
第二种方法:贪心算法
举一个例子来说,2,1,4,5,6,3,3,4,8,4
(1)第一个数2来说,由于后面一个数不等于2,所以当前序列为2,1
(2)对于当前序列,我们需要一个比1大的数,而4>1,所以当前序列为2,1,4
(3)现在我们需要一个比4小的数,但是5>4,所以这里用5替代4,这里使用的贪心规则(使用5肯定比用4容易遇到更小的数,所以用大的数代替小的数,需要一个比当前数大时和这个类似),所以序列为2,1,5
(4)同(3)这里变成2,1,6
(5)这里需要比6小,3比6小所以这里变为2,1,6,3
(6)需要比3大的,而3=3,所以序列还是为2,1,6,3
(7)需要比3大的,而4>3,所以序列2,1,6,3,4
......
最后得到序列为2,1,6,3,8,4,返回值为6
代码: 为了思路清晰,所以代码写的比较复杂......
public class Solution { public int wiggleMaxLength(int[] nums) { if(nums==null||nums.length==0) return 0; if(nums.length==1) return 1; int res=0; int i=0; while(i<nums.length-1){ //删除最开始 相同的数 ,如2,2,2,3,1 if(nums[i]==nums[i+1]){ i++; }else{ break; } } nums[res] = nums[i]; if(i==nums.length-1){ //给出的数组为2,2,2,2,2这种格式 return 1; }else{ res++; i++; nums[res]=nums[i]; //得出前两个的值,并得出初始的flag int flag=nums[1]-nums[0]; //大于0,==0,或者小于0 while(i<nums.length-1){ if(flag==0){ i++; }else if(flag>0){ //前面是递增,所以现在需要减 if(nums[i+1]-nums[res]<0){ //确实是递减,加入即可 flag=nums[i+1]-nums[res]; res++; i++; nums[res]=nums[i]; }else{ i++; nums[res] = nums[i]; //将当前序列最后一个替换为后一个比较大的数 } }else if(flag<0){ //前面是递减,所以现在需要增 if(nums[i+1]-nums[res]>0){ //确实是递减,加入即可 flag=nums[i+1]-nums[res]; res++; i++; nums[res]=nums[i]; }else{ //需要一个高大的数,所以当前数更小的话,更加容易找到符合要求的数 i++; nums[res] = nums[i]; //将当前序列最后一个替换为后一个比较小的数 } } } } // System.out.println(res+1); // for(int j=0;j<=res;j++) // System.out.print(nums[j]+" "); return res+1; } }