这题是要找能构成相邻元素的差一正一负交替的最长子序列。
用两个指针,left和right。left初始指向0位置,right指向1位置(如果原数组长度只有1会直接退出)。初始化题目要求的子序列长度为1,然后自定义一个求数的符号的函数(正数返回1,负数返回-1),用gap保存上一组nums[right] - nums[left]的差的正负型。注意每一轮首先要把right向右移动跳过重复的值,比如对于[0,0,0],结果应当是1。然后进入下一段逻辑,如果是初始的情况直接跳过(cnt=1时),否则,一直右移right直到nums[right] - nums[left] 的正负型和上一组的正负型相反停下。停下之后还有很重要的一步,一直右移right找到单调性变化的拐点,找到之后,left变为right,right++,cnt++,同时要注意right不能越界。这样找到的子序列每个元素一定是极大值/极小值,保证了子序列一定是最长的。
举例说明,比如输入[33,33,53,12,64,50,41,45,21,9]。初始化cnt=1, left = 0, right = 1。第一轮,right右移到2,跳过重复的33,此时是第一轮,所以cnt++,gap = 53 - 33 的正负型 = 1,left = 2, right = 3;第二轮,一直右移right直到nums[right] - nums[left] 为负,于是right = 3, left = 2, gap = -1, cnt = 3;第三轮,left = 3, right = 4, cnt = 4;第四轮,left = 4, right = 5, cnt = 5,注意此时没有结束,应当继续右移right,因为此时在递减,往后一位还在递减,我们希望每次保留的都是极大值/极小值,因此right右移到6。后面的每轮都是类似,直到right越界后退出。
此题重点是中途保存的一定是极大值/极小值,否则最终的子序列不是最长的。
class Solution {
public int wiggleMaxLength(int[] nums) {
int left = 0, right = 1;
int cnt = 1;
int gap = 0;
while (right < nums.length) {
while (right < nums.length && nums[right] == nums[left]) {
right++;
}
if (right >= nums.length) {
break;
}
if (cnt != 1) {
while (right < nums.length && sign(nums[right] - nums[left]) != -gap) {
right++;
}
if (right >= nums.length) {
break;
}
}
cnt++;
gap = sign(nums[right] - nums[left]);
while(right + 1 < nums.length && sign(nums[right + 1] - nums[right]) == gap){
right++;
}
left = right;
right++;
}
return cnt;
}
private int sign(int n) {
if (n > 0) {
return 1;
} else if (n < 0) {
return -1;
}
return 0;
}
}