376. Wiggle Subsequence

2018年01月21日,第一篇刷题记录

Posted by dafei on January 21, 2018

376. Wiggle Subsequence


Description

link

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.

Example: 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


Solution

题意:从给出序列中寻找最长的摆动序列并输出该子序列长度,摆动序列定义是按照一增一减的序列,其相邻的差分别一正一负。

1. 贪心法 Greedy

序列从最左开始,找连续递增序列的最大值为转折点,以及连续递减最小值为转折点,计数,最后得到的cnt值即为摆动序列并输出该子序列长度。分析图如下所示,不在拐点处的摆动序列的长度一定小于等于选择拐点处(峰值)的摆动序列。 Wiggle-Subsequence 初始代码如下 (Java)

class Solution {
    public int wiggleMaxLength(int[] nums) {
        if(nums.length < 2)
        {
            return nums.length;
        }
        else
        {
            int temp = nums[0];
            int cnt = 1;
            int flag = 0;
            if(nums[1] > nums[0]) {
                flag = 1;
                cnt ++;
                temp = nums[1];
            } else if (nums[1] < nums[0]) {
                flag = -1;
                cnt ++;
                temp = nums[0];
            }
            
            for(int i=2; i<nums.length; i++)
            {
                if(nums[i] > nums[i-1]) {
                    if(flag == 1) {
                        if(nums[i] > temp) {
                            temp = nums[i];
                        }
                    }
                    else {
                        flag = 1;
                        cnt++;
                        temp = nums[i];
                    }
                }
                else if(nums[i] < nums[i-1]) {
                    if(flag == -1) {
                        if(nums[i] < temp) {
                            temp = nums[i];
                        }
                    } else {
                        flag = -1;
                        cnt++;
                        temp = nums[i];
                    }
                }
            }
            return cnt;
        }
    }
}

优化后的代码如下(Java)

class Solution {
    public int wiggleMaxLength(int[] nums) {
        if(nums.length < 2)
        {
            return nums.length;
        }
        else
        {
            int prediff = nums[1] - nums[0];
            int cnt = (prediff != 0) ? 2 : 1;
            for(int i=2; i<nums.length; i++)
            {
                int diff = nums[i] - nums[i-1];
                if((diff > 0 && prediff <= 0) || (diff < 0 && prediff >= 0))
                {
                    cnt++;
                    prediff = diff;
                }
            }
            return cnt;
        }
    }
}

Complexity Analysis: · Time complexity : O(n). We traverse the given array once. · Space complexity : O(1). No extra space is used.


2. 动态规划 Dynamic Programming

Linear Dynamic Programming(线性动态规划) 当前元素与前一个元素的关系有三种:大于、等于、小于。up[i]表示以第i个元素结尾的最后是上升的抖动序列的长度,down[i]表示以第i个元素结尾的最后是下降的抖动序列的长度。

  • nums[i] > nums[i-1],表示序列在此处上升,所以之前的序列必须是下降的,则up[i] = down[i-1]+1,down[i] = down[i-1];
  • nums[i] < nums[i-1],表示序列在此处下降,所以之前的序列必须是上升的,则down[i] = up[i-1]+1,up[i] = up[i-1];
  • nums[i] == nums[i-1],表示序列在此处没有改变,则down[i] = down[i-1],up[i] = up[i-1];
  • 最后找up[length-1]和down[length-1]最大的一个即可。

代码如下(Java)

public class Solution {
    public int wiggleMaxLength(int[] nums) {
        if (nums.length < 2)
            return nums.length;
        int[] up = new int[nums.length];
        int[] down = new int[nums.length];
        up[0] = 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]);
    }
}

Complexity Analysis · Time complexity : O(n). Only one pass over the array length. · Space complexity : O(n). Two arrays of the same length are used for dp.

Space-Optimized Dynamic Programming(空间优化的动态规划)

public class Solution {
    public int wiggleMaxLength(int[] nums) {
        if (nums.length < 2)
            return nums.length;
        int down = 1, up = 1;
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] > nums[i - 1])
                up = down + 1;
            else if (nums[i] < nums[i - 1])
                down = up + 1;
        }
        return Math.max(down, up);
    }
}

Complexity Analysis · Time complexity : O(n). Only one pass over the array length. · Space complexity : O(1). Constant space is used.