package com.freetymekiyan.algorithms.level.medium; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * 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. * <p> * 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. * <p> * 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. * <p> * Examples: * Input: [1,7,4,9,2,5] * Output: 6 * The entire sequence is a wiggle sequence. * <p> * 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,5,10,13,10,16,8]. * <p> * Input: [1,2,3,4,5,6,7,8,9] * Output: 2 * Follow up: * Can you do it in O(n) time? * <p> * Tags: Dynamic Programming, Greedy */ public class WiggleSubsequence { private WiggleSubsequence w; /** * DP, Greedy. * Use two vars to record the count of increasing-first and decreasing-first sequences. * Then loop through the array from second number. * If current number is larger than previous one, it means we can extend our last decreasing sequence length by 1. * So inc = dec + 1. * Otherwise, dec = inc + 1. * Return the max of these two counts. */ public int wiggleMaxLength(int[] nums) { if (nums == null || nums.length == 0) { return 0; } int inc = 1; int dec = 1; for (int i = 1; i < nums.length; i++) { if (nums[i] > nums[i - 1]) { inc = dec + 1; } else if (nums[i] < nums[i - 1]) { dec = inc + 1; } } return Math.max(inc, dec); } @Before public void setUp() { w = new WiggleSubsequence(); } @Test public void testExamples() { int[] nums = {1, 7, 4, 9, 2, 5}; Assert.assertEquals(6, w.wiggleMaxLength(nums)); nums = new int[]{1, 17, 5, 10, 13, 15, 10, 5, 16, 8}; Assert.assertEquals(7, w.wiggleMaxLength(nums)); nums = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; Assert.assertEquals(2, w.wiggleMaxLength(nums)); } @After public void tearDown() { w = null; } }