Skip to content

Files

Latest commit

4c4e548 · Feb 25, 2022

History

History
This branch is 802 commits behind wisdompeak/LeetCode:master.

376.Wiggle-Subsequence

376.Wiggle-Subsequence

解法1:贪心

我们将整个数组的函数曲线画出来,其实只要数有多少个“拐点”,就是最后的答案了。道理也很简单,最长的wiggle序列,一定会是尽量充分利用所有的拐点。

这里特别要注意的是如果有两个相邻的点相同怎么处理?算是“拐点”吗?不一定。我们只有定义某点斜率前后的正负号的改变才是算拐点。举个例子,当nums[i]>nums[i-1]的时候,这中间的斜率k为正;但如果之前的nums[i-2]==nums[i-1]的话,我们无法判定斜率是否改变了符号。因此我们需要记录下nums[i-1]之前最近的一个非零斜率k',查看它的正负号再与当前的k作比较。所以我们每次更新某两个相邻点之间的斜率的时候,如果是零,我们认为这段斜率依然保持为之前最近的一个非零斜率。

核心代码如下

        for (int i=1; i<nums.size(); i++)
        {
            int dir_pre = dir;
            
            if (nums[i]-nums[i-1]>0)
                dir = 1;
            else if (nums[i]-nums[i-1]<0)
                dir = -1;
            else   
                dir = dir_pre;

            if (dir!=dir_pre)
                ret++;
        }

解法2:DP

设计两个状态变量:p表示截止目前为止,最后一个元素是上升趋势的最长wiggle子序列;q表示截止目前为止,最后一个元素是下降趋势的最长wiggle子序列。

首先我们要有这样一个概念。无论当前元素x是什么,p序列的最后一个元素要么是x,要么只能是在x前面、但是比x大的元素。反证:如果存在一个元素y在x前面、且比x要小,那么这个将y从p序列的结尾里去掉、改成x加入p序列的结尾,同样不影响p序列的性质和长度。同理,无论当前元素x是什么,q序列的最后一个元素要么是x,要么只能是在x前面、但是比x小的元素。

回到我们的问题。我们每查看一个数字,尝试更新两个变量p和q。当nums[i]>nums[i-1]大时,由前面可知,原先q序列的结尾元素一定比nums[i]小,于是再接上nums[i]的话q序列一定不会变的更长。同时,原先q序列的结尾一定比nums[i]小,接上nums[i]之后,就可以得到一个新的p的序列。故有q不变,p=q+1.

类似地,当nums[i]<nums[i-1]小时,由前面可知,原先p序列的结尾元素一定比nums[i]大,于是再接上nums[i]的话p序列一定不会变的更长。同时,原先p序列的结尾一定比nums[i]大,接上nums[i]之后,就可以得到一个新的q的序列。故有p不变,q=p+1.

因为无法确定最长wiggle序列的最后一段是上升还是下降,因此最后的答案是在p和q之间选最大值。

Leetcode Link