动态规划:找到锯齿状的最长子序列
任何人都可以帮助我理解 http://www.topcoder.com/stat?c=problem_statement&pm=1259&rd=4493 之
字形序列是交替增加和减少的一种。因此,1 3 2 是锯齿形,但 1 2 3 不是。任何一个或两个元素的序列都是锯齿形的。我们需要找到给定序列中最长的锯齿形子序列。子序列意味着元素不必是连续的,就像最长递增子序列问题一样。因此,1 3 5 4 2 可以有 1 5 4 作为锯齿形子序列。我们对最长的一个感兴趣。
我知道这是一个动态规划问题,它与 如何使用动态规划确定最长递增子序列?。
我认为任何解决方案都需要一个外部循环来迭代不同长度的序列,并且内部循环必须迭代所有序列。
我们将以索引 i 结尾的最长之字形序列存储在另一个数组中,例如索引 i 处的 dpStore。因此,中间结果被存储,并且可以在以后重用。这部分对于所有动态规划问题都是通用的。后来我们找到全局最大值并将其返回。
我的解决方案肯定是错误的,粘贴在这里是为了展示我到目前为止所得到的。我想知道我哪里错了。
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;
}
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
int zigzag(int[] a) {
}
int zigzag(int[] a) {
}
def ZigZag(tup):
def ZigZag(tup):
选择局部最大值和局部最小值,非常简单。
Pick local maxima and local minima, very simple.
这就是您链接到的问题所说的:
这与您在帖子中描述的完全不同。下面解决实际的topcoder问题。
示例:
然后取两个 dp 数组的最大值。
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.这是一个更简单的解决方案
让原始数组 A 的长度为 n。构建另一个长度为 n-1 且仅包含 0 和 1 的数组 B。如果a[i]-a[i+1]>=0,则B[i]=0,否则B[i]=1。这可以在O(n)内完成。现在我们有一个只有 0 和 1 的数组,现在的问题是找到交替的连续 0 和 1。 B of 0 中的连续子数组数组将由其任意一个元素表示。例如:
如果 B = [0,0,0,0,0, 1,0,0,0,1,0,1,1,1,0] 那么我们可以将 B 简化为 Br = [0,1,0 ,1,0,1,0]在O(n)中,实际上我们只需要找到Br的大小,只需一次迭代即可完成。我的朋友就是给定问题的答案。因此总复杂度为 O(n) + O(n) = O(n)。
换句话说:
保留第一个元素。然后找到序列中单调增长或收缩的部分,并保留所有这些序列中的最后一个元素。
更新:您需要在此过程中得出的答案中加一,因为您正在计算之字形,而不是列表的长度。当心栅栏柱问题:https://betterexplained .com/articles/learning-how-to-count-avoiding-the-fencepost-problem/
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/
还有一种贪婪的方法。
取第一个元素。然后找出包含第一个元素的连续序列中的最小或最大元素并选择它。
也就是说,如果序列是
1, 5, 7, 9, 2,4
,首先选择 1,然后选择 9,因为 9 是连续序列1, 5, 7, 9.
.以同样的方式进行,选择2和5。
使用相同的方法,为示例计算的子序列
为:
1, 17, 5, 15, 5, 16, 8
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
或者你可以使用贪心算法
or you can use greedy algorithm
实际上我认为得分最高的答案是正确的(IVlad)。但我很确定动态编程部分(外循环)是不需要的。
使用贪心方法,我们可以通过操作:
positive_end_seq[0] = 1
和 < code>negative_end_seq[0] = 1,所有i
的两个数组都包含以 pos/neg 结尾的最长子序列的长度第 i 个元素。我们不必查看0..i-2
元素,最好能证明这一点。时间复杂度是
O(n)
当然,pos/neg数组现在可以用计数器代替,这里是Java代码
Actually I think that answer with highest score is correct (IVlad's). But I'm pretty sure that the dynamic programming part (outer loop) is not necessary.
A greedy approach is used and we can obtain
positive_end_seq[i]
andnegative_end_seq[i]
by operations:positive_end_seq[0] = 1
andnegative_end_seq[0] = 1
, both arrays for alli
's contain length of the longest subsequence with pos/neg ending ini
-th element. We don't have to look at0..i-2
elements, and it would be nice to prove that.Time complexity is
O(n)
Of course, pos/neg array can be replaced by counters now, here is code in Java
这是我对简单贪婪实现的看法。
就像其他人之前提到的那样,您只需要查看最后三个点的曲折即可。
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.
这是如何在 O(n) 中完成的
Here is how did it in O(n)