Can anyone please help me understand the core logic behind the solution to a problem mentioned at http://www.topcoder.com/stat?c=problem_statement&pm=1259&rd=4493
A zig zag sequence is one that alternately increases and decreases. So, 1 3 2 is zig zag, but 1 2 3 is not. Any sequence of one or two elements is zig zag. We need to find the longest zig zag subsequence in a given sequence. Subsequence means that it is not necessary for elements to be contiguous, like in the longest increasing subsequence problem. So, 1 3 5 4 2 could have 1 5 4 as a zig zag subsequence. We are interested in the longest one.
I understand that this is a dynamic programming problem and it is very similar to How to determine the longest increasing subsequence using dynamic programming?.
I think any solution will need an outer loop that iterates over sequences of different lengths, and the inner loop will have to iterate over all sequences.
We will store the longest zig zag sequence ending at index i in another array, say dpStore at index i. So, intermediate results are stored, and can later be reused. This part is common to all Dynamic programming problems. Later we find the global maximum and return it.
My solution is definitely wrong, pasting here to show what I've so far. I want to know where I went wrong.
private int isZigzag(int[] arr)
{
int max=0;
int maxLength=-100;
int[] dpStore = new int[arr.length];
dpStore[0]=1;
if(arr.length==1)
{
return 1;
}
else if(arr.length==2)
{
return 2;
}
else
{
for(int i=3; i<arr.length;i++)
{
maxLength=-100;
for(int j=1;j<i && j+1<=arr.length; j++)
{
if(( arr[j]>arr[j-1] && arr[j]>arr[j+1])
||(arr[j]<arr[j-1] && arr[j]<arr[j+1]))
{
maxLength = Math.max(dpStore[j]+1, maxLength);
}
}
dpStore[i]=maxLength;
}
}
max=-1000;
for(int i=0;i<arr.length;i++)
{
max=Math.max(dpStore[i],max);
}
return max;
}
int zigzag(int[] a) {
}
This is a simpler solution
Let the original array A be of length n. Build another array B of length n-1 of only 0s and 1s. B[i] = 0 if a[i]-a[i+1] >=0 else B[i] = 1. This can be done in O(n). Now we have an array of only 0s and 1, now the problem is to find alternating continuous 0s and 1s. A continuous sub array array in B of 0s will be represented by any one of its elements. For example: If B is = [0,0,0,0,0, 1,0,0,0,1,0,1,1,1,0] then we can reduce B to Br which = [0,1,0,1,0,1,0] in O(n), in fact we just need to find the size of Br which can be done by just one iteration. And that my friend is the answer to the given problem. So total complexity is O(n) + O(n) = O(n). In other words: Keep the first element. Then find the monotone growing or shrinking parts of the sequence and keep the last element from all of these sequences.
UPDATE: You need to add one to the answer coming out of this process, because you are counting the zigzags, not the length of the list. Beware of the fence post problem: https://betterexplained.com/articles/learning-how-to-count-avoiding-the-fencepost-problem/
There is a greedy approach also.
Take the first element. Then find out the minimum or maximum element in the contiguous sequence including the first element and select it.
That is if the sequence is
1, 5, 7, 9, 2,4
, first select 1, and then 9 because 9 is the maximum in the contiguous sequence1, 5, 7, 9
.Proceed in the same manner and select 2 and 5. Using same approach, the subsequence computed for the example:
is:
1, 17, 5, 15, 5, 16, 8
This is what the problem you linked to says:
This is completely different from what you described in your post. The following solves the actual topcoder problem.
Example:
Then just take the max of both
dp
arrays.This is my take on a simple greedy implementation.
Like others have previously mentioned, you simply need to look at the zag'ing of the three last points.