Daily LeetCode 376. Wiggle Subsequence

https://leetcode.com/problems/wiggle-subsequence/

Medium

问题描述:

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

1
2
3
Input: [1,7,4,9,2,5]
Output: 6
Explanation: The entire sequence is a wiggle sequence.

Example 2:

1
2
3
Input: [1,17,5,10,13,15,10,5,16,8]
Output: 7
Explanation: There are several subsequences that achieve this length. One is [1,17,10,13,10,16,8].

Example 3:

1
2
Input: [1,2,3,4,5,6,7,8,9]
Output: 2

Follow up:
Can you do it in O(n) time?

题目分析及代码:

题目给出了一个称作wiggle sequence的定义,这是一个摆动序列,满足nums[i-1]<nums[i]>nums[i+1],我们需要从给定输入中找出一个最长的子摆动序列。

方法1:

对于数组中的每个元素,可能有三种状态:

  • 后一个数大于这个数,此时记做up
  • 后一个数小于这个数,此时记做down
  • 后一个数等于这个数

我们维护两个数组,来记录当前情况下(index=iwiggle sequence的最长长度:

  • 后一个数大于当前数时,这个序列是“向上摆”的,想要确保该序列是摆动序列,我们需要确保当前数与前一个数的关系是“向下摆”,即当前数小于前一个数。此时更新up数组,up[i]=down[i-1]+1;同时,down数组在当前位置的值与先前相同,不做更新,down[i]=down[i-1]
  • 后一个数小于当前数时,与上述情况刚好相反,此时,up[i]=up[i-1]down[i]=up[i-1]+1
  • 两数相等时,不做任何更新操作,up[i]=up[i-1], down[i]=down[i-1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def wiggleMaxLength(nums):
up = [1 for i in range(len(nums))]
down = [1 for i in range(len(nums))]

for i in range(1, len(nums)):
if nums[i] > nums[i - 1]:
up[i] = down[i - 1] + 1
down[i] = down[i - 1]
elif nums[i] < nums[i - 1]:
down[i] = up[i - 1] + 1
up[i] = up[i - 1]
else:
up[i], down[i] = up[i - 1], down[i - 1]

return max(up[-1], down[-1])

方法2:

贪心策略,维护updown两个变量,均初始化为1,遍历数组,当前元素大于前一个元素时,up = down + 1;当前元素小于前一个元素时,down = up + 1

与动态规划思想相同,但节省了空间。

1
2
3
4
5
6
7
8
9
def wiggleMaxLength(nums):
up, down = 1, 1
for i in range(1, len(nums)):
if nums[i] > nums[i - 1]:
up = down + 1
elif nums[i] < nums[i - 1]:
down = up + 1

return min(len(nums), max(up, down))