输入一个整型数组nums,该数组表示一个序列,序列中元素的大小顺序是随机的。从数组中去除若干个元素后,可以得到wiggle sequence。求能够得到的最长wiggle sequence的长度。
wiggle sequence是一种满足相邻元素的差值严格遵循正负交替特点的序列。长度为1的序列都算作wiggle sequence。
例如:
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
---------------------------
题目要求时间复杂度为O(n),可以考虑用空间换时间——采用DP(动态规划)的思想来解决这个问题。
(1)首先考虑一般情况
创建两个辅助数组lengths和diffs,其元素分别用于记录序列从最左边到当前位置为止,所能得到的最长wiggle sequence的长度和当前元素在wiggle sequence中相对于前一个元素的差值。
在已知lengths[k] 和diffs[k]的情况下,可以用下面的方法将lengths和diffs推进到k+1:
首先求出序列中第k+1个元素与第k个元素的差值,即diff = nums[k + 1] – nums[k]。根据diff的不同进行不同的处理:
1)diff = 0,说明这两个元素相等,此时lengths[k + 1] = lengths[k],diffs[k + 1] = diffs[k];
2)diff与diffs[k]同为正数或同为负数,说明这两个元素中需要去除一个,因此到k+1位置为止的最长wiggle subsequence长度与k的相同,此时lengths[k + 1] = lengths[k],diffs[k + 1] = diff;
2)diff与diffs[k]不同号,说明可以在k的最长wiggle subseequence的基础上追加一个元素nums[k + 1]。此时lengths[k + 1] = lengths[k] + 1,diffs[k + 1] = diff。
(2)空间复杂度的优化
事实上,对于上述两个辅助数组lengths和diffs,每次迭代时都只用到了最近的一个元素。因此,可以将这两个数组简化为两个变量——maxlen和diff。
(3)考虑边界条件
上述算法从序列的第2个元素开始处理,直到序列的最后一个元素,最后得到的lengths的最后一个元素即为整个序列的最长wiggle subsequence的长度。
如果输入序列含有0元素,那么直接返回0。另外,diff的初始值没有意义,因此需要在迭代时进行判断。
实现代码如下:
class Solution {
public int wiggleMaxLength(int[] nums) {
if(nums.length == 0) {
return 0;
}
int maxlen = 1, diff = 0;
for(int i = 1; i < nums.length; i++) {
int newDiff = nums[i] - nums[i - 1];
if(newDiff != 0 && (diff == 0 || newDiff * diff < 0)) {
diff = newDiff;
maxlen++;
}
}
return maxlen;
}
}
算法只需要进行一轮迭代并且只用到了有限个状态变量,因此时间复杂度为O(n),空间复杂度为O(1)。