leetcode 376

这题是要找能构成相邻元素的差一正一负交替的最长子序列。

用两个指针,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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值