[LeetCode] Wiggle Subsequence 擺動子序列


 

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.

Examples:

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

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

Credits:
Special thanks to @agave and @StefanPochmann for adding this problem and creating all test cases.

 

這道題給我了我們一個數組,讓我們求最長擺動子序列,關於擺動Wiggle數組,可以參見LC上之前的兩道題Wiggle SortWiggle Sort II。題目中給的tag說明了這道題可以用DP和Greedy兩種方法來做,那么我們先來看DP的做法,我們維護兩個dp數組p和q,其中p[i]表示到i位置時首差值為正的擺動子序列的最大長度,q[i]表示到i位置時首差值為負的擺動子序列的最大長度。我們從i=1開始遍歷數組,然后對於每個遍歷到的數字,再從開頭位置遍歷到這個數字,然后比較nums[i]和nums[j],分別更新對應的位置,參見代碼如下:

 

解法一:

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if (nums.empty()) return 0;
        vector<int> p(nums.size(), 1);
        vector<int> q(nums.size(), 1);
        for (int i = 1; i < nums.size(); ++i) {
            for (int j = 0; j < i; ++j) {
                if (nums[i] > nums[j]) p[i] = max(p[i], q[j] + 1);
                else if (nums[i] < nums[j]) q[i] = max(q[i], p[j] + 1);
            }
        }
        return max(p.back(), q.back());
    }
};

 

題目中有個Follow up說要在O(n)的時間內完成,而Greedy算法正好可以達到這個要求,這里我們不在維護兩個dp數組,而是維護兩個變量p和q,然后遍歷數組,如果當前數字比前一個數字大,則p=q+1,如果比前一個數字小,則q=p+1,最后取p和q中的較大值跟n比較,取較小的那個,參見代碼如下:

 

解法二:

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        int p = 1, q = 1, n = nums.size();
        for (int i = 1; i < n; ++i) {
            if (nums[i] > nums[i - 1]) p = q + 1;
            else if (nums[i] < nums[i - 1]) q = p + 1;
        }
        return min(n, max(p, q));
    }
};

 

類似題目:

Wiggle Sort

Wiggle Sort II

 

參考資料:

https://discuss.leetcode.com/topic/51893/two-solutions-one-is-dp-the-other-is-greedy

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM