leetCode 376. Swing sequence greedy algorithm

If the difference between consecutive numbers alternates strictly between positive and negative numbers, the sequence of numbers is called  a wobble sequence. The first difference (if present) may be positive or negative. Sequences with only one element or two unequal elements are also considered wobble sequences.

  • For example,  [1, 7, 4, 9, 2, 5] it is a  swing sequence  because the differences  (6, -3, 5, -7, 3) alternate between positive and negative values.

  • In contrast, the sum is [1, 4, 7, 2, 5] not  [1, 7, 4, 5, 5] a oscillating sequence, the first one because its first two differences are both positive, and the second one because its last difference is zero.

A subsequence  can be obtained by deleting some (or not) elements from the original sequence, leaving the remaining elements in their original order. Given an array of integers  nums , return  the length of the longest subsequencenums  in  the wobble  sequence   .

Example 1:

Input: nums = [1,7,4,9,2,5]
 Output: 6
 Explanation: The entire sequence is a swing sequence, and the difference between each element is (6, -3, 5, -7, 3) .

Example 2:

Input: nums = [1,17,5,10,13,15,10,5,16,8]
 Output: 7
 Explanation: This sequence contains several wobble sequences of length 7.
One of them is [1, 17, 10, 13, 10, 16, 8], and the difference between the elements is (16, -7, 3, -3, 6, -8).

Example 3:

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

>>Ideas and analysis

Idea 1: Greedy idea

  • Local optimum : Delete the nodes on the monotonic slope (excluding nodes at both ends of the monotonic slope), then this slope can have two local peaks
  • Overall optimal : the entire sequence has the most local peaks, thus achieving the longest swing sequence

Try being greedy: the local optimum leads to the global optimum, and no counterexamples can be given! ! !

In actual operation, there is no need to perform deletion operations. Since the question requires the length of the longest swing subsequence, you only need to count the number of local peaks in the array (equivalent to deleting nodes on a single slope and then counting the lengths) . That is where greed takes hold.

(1) How to express a fluctuation?

curdiff = nums[i+1] - nums[i];
prediff = nums[i] - nums[i-1];

If or  when there are fluctuations, statistics are neededprediff < 0 && curdiff > 0 prediff > 0 && curdiff < 0 

(2) How to solve the problem if there is a flat slope? Let’s continue looking down~

There are two types of flat slopes: one is a flat slope between the top and bottom, and the other is monotonous with a flat slope in the middle. 

① Situation 1: There is a flat slope in the uphill and downhill slopes

For example, [1,2,2,2,1], its swing sequence length is 3, that is, when we delete, we either delete the three 2s on the left, or delete the three 2s on the right.

In the figure, when i points to the first 2, prediff > 0 && curdiff = 0 , and when i points to the last 2, prediff = 0 && curdiff < 0

If the rule of deleting the three 2s on the left is adopted, then when i points to the first 2, prediff = 0 && curdiff < 0, a peak value will also be recorded. This is because it removes the peaks left by all the same elements before.

So the condition for recording the peak value here can allow prediff = 0 , that is: or   . That is to say, when the same numbers are consecutive, prediff = 0, curdiff < 0 or > 0, which is the trough of the wave.prediff <= 0 && curdiff > 0 prediff >= 0 && curdiff < 0

② Case 2: Both ends of the array

Question thinking (O_O)? When counting peak values, how to count the leftmost and rightmost sides of the array?

Example: sequence [2,5], the swing sequence is 2.

When we mentioned prediff = nums[i] - nums[i-1] and curdiff = nums[i+1] - nums[i] above , we can see that at least three numbers are needed to calculate. Because it relies on statistical differences to calculate the number of peaks, it is necessary to consider the special cases of the leftmost and rightmost sides of the array. At this time, the sequence array only has two numbers. How to combine our judgment rules?

Let's assume that there is another number in front of the array, that is, the sequence [2,5] is assumed to be [2,2,5]. At this time, the slope prediff = 0. This is exactly the situation discussed above, so it can also be recorded as a trough

In view of the above situation, result is initially 1 (default is a peak on the far right), at this time curdiff > 0 && prediff <= 0, then result++ (the peak value on the left is calculated), and the final result is 2 (the number of peaks is 2 , that is, the length of the swing sequence is 2)

So you can initialize prediff = 0, result = 1

③ Case 3: There is a flat slope in the monotonic slope

In the figure above, the length of the longest swing sequence can be calculated to be 3, but the result should actually be 2. This is because the above graph updates prediff in real time without restrictions, which causes flat slopes in monotonicity to be counted as peaks.

When should I update prediff ? You only need to update prediff when the slope swing changes , so that prediff will not change when there is a flat slope in the monotonic interval, and there will be no misjudgment!

>>Analyze the above two pictures and think about the questions (O_O)?

The problem is that prediff is always updated following curdiff. In fact, there is no need for prediff to follow curdiff for real-time transformation. Prediff only needs to count when the slope changes and record the original direction of the slope. For example, at the first position 2 , prediff changes because it defaults to a flat slope at 1 (case 2). Then when there is a change, prediff records the initial value of the slope, that is The direction of the initial slope. There is no need to change the subsequent prediff. So when will it change? Unless the direction of the slope changes, that is to say, a swing is encountered, then prediff can record the slope direction of the next slope. In this case, prediff only records the initial slope when the slope changes. What are the benefits of this? Prediff will not change when encountering flat slopes. In this way, in the logic of this code, the third 2 will not be recorded as a swing (because in the third 2, if prediff is always updated in real time, prediff = 0, curdiff > 0 will appear. This situation In fact, it is the second scenario, which will be considered a swing) . Therefore, the solution is: prediff only records the initial slope of the next slope when the swing occurs, and then prediff does not need to change it until the next swing occurs and the direction of the slope is changed. Prediff can go again Change so that you can bypass this flat slope situation. How should it be changed when reflected in the code? You can put prediff=curdiff inside if. When there is a swing, update the prediff so that you can bypass the situation of flat slopes.

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if(nums.size() <= 1) return nums.size();
        int prediff = 0; // 前一对差值
        int curdiff = 0; // 当前一对差值
        int result = 1; // 记录峰值个数,序列默认序列最右边有一个峰值
        for(int i=0;i<nums.size()-1;i++) {
            curdiff = nums[i+1] - nums[i];
            // prediff=curdiff放在if里面,为的是处理单调有平坡的这种情况
            if((prediff >=0 && curdiff<0) || (prediff <=0 && curdiff>0)) { // 出现峰值
                result++;
                prediff = curdiff; // 注意这里,只在摆动变化的时候更新prediff
            }
        }
        return result;
    }
};
  • Time complexity: O(n)
  • Space complexity: O(1)

prediff = curdiff is placed inside if in order to deal with the situation of monotony and flat slope. If placed outside if, the misjudgment mentioned above will occur! ! !

Reference and recommended articles and videos

Code Random Record (programmercarl.com)

Greedy algorithm, looking for details in the swing! | LeetCode: 376. Swing sequence_bilibili_bilibili

Class screenshots from Code Caprice:

Guess you like

Origin blog.csdn.net/weixin_41987016/article/details/133466509