Algorithm 动态规划:找到Z字形的最长子序列

Algorithm 动态规划:找到Z字形的最长子序列,algorithm,dynamic-programming,Algorithm,Dynamic Programming,有人能帮我理解一下在会议上提到的问题解决方案背后的核心逻辑吗 锯齿形序列是交替增加和减少的序列。所以,1232是之字形的,但1233不是。一个或两个元素的任何序列都是之字形的。我们需要找到给定序列中最长的Z字型子序列。子序列意味着元素不必是连续的,就像最长递增子序列问题一样。因此,1 35 4 2可以将1 5 4作为之字形子序列。我们对最长的那个感兴趣 我知道这是一个动态规划问题,它非常类似于 我认为任何解决方案都需要一个外循环来迭代不同长度的序列,而内循环必须迭代所有序列 我们将在另一个数组中

有人能帮我理解一下在会议上提到的问题解决方案背后的核心逻辑吗

锯齿形序列是交替增加和减少的序列。所以,1232是之字形的,但1233不是。一个或两个元素的任何序列都是之字形的。我们需要找到给定序列中最长的Z字型子序列。子序列意味着元素不必是连续的,就像最长递增子序列问题一样。因此,1 35 4 2可以将1 5 4作为之字形子序列。我们对最长的那个感兴趣

我知道这是一个动态规划问题,它非常类似于

我认为任何解决方案都需要一个外循环来迭代不同长度的序列,而内循环必须迭代所有序列

我们将在另一个数组中存储以索引i结尾的最长的Z字型序列,比如dpStore在索引i。因此,中间结果被存储起来,以后可以重用。这一部分是所有动态规划问题的通用部分。稍后我们找到全局最大值并返回它

我的解决方案肯定是错误的,粘贴到这里来显示我到目前为止所做的。我想知道我哪里出错了

    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; 
}
private int是之字形(int[]arr)
{
int max=0;
int maxLength=-100;
int[]dpStore=新int[arr.length];
dpStore[0]=1;
如果(arr.length==1)
{
返回1;
}
否则如果(arr.length==2)
{
返回2;
}
其他的
{           

对于(int i=3;i这就是您链接到的问题所说的:

如果连续数字之间的差严格地在正负之间交替,则一个数字序列称为之字形序列。第一个差(如果存在)可以是正的或负的。少于两个元素的序列通常是一个之字形序列

例如,1,7,4,9,2,5是之字形序列,因为差值(6,-3,5,-7,3)交替为正和负。相反,1,4,7,2,5和1,7,4,5,5不是之字形序列,第一个是因为其前两个差值为正,第二个是因为其最后一个差值为零

给定一个整数序列,sequence,返回序列中最长子序列的长度,该子序列是一个之字形序列。从原始序列中删除一定数量的元素(可能为零),使其余元素保持其原始顺序,即可获得子序列

这与你在文章中描述的完全不同。下面解决了topcoder的实际问题

dp[i, 0] = maximum length subsequence ending at i such that the difference between the
           last two elements is positive
dp[i, 1] = same, but difference between the last two is negative

for i = 0 to n do     
   dp[i, 0] = dp[i, 1] = 1

   for j = 0 to to i - 1 do
    if a[i] - a[j] > 0
      dp[i, 0] = max(dp[j, 1] + 1, dp[i, 0])
    else if a[i] - a[j] < 0
      dp[i, 1] = max(dp[j, 0] + 1, dp[i, 1])
    
dp[i,0]=以i结尾的最大长度子序列,使得
最后两个因素是积极的
dp[i,1]=相同,但后两者之间的差值为负值
对于i=0到n do
dp[i,0]=dp[i,1]=1
对于j=0到i-1 do
如果a[i]-a[j]>0
dp[i,0]=max(dp[j,1]+1,dp[i,0])
否则,如果a[i]-a[j]<0
dp[i,1]=max(dp[j,0]+1,dp[i,1])
例如:

i        = 0  1   2  3   4   5   6   7  8   9
a        = 1  17  5  10  13  15  10  5  16  8 
dp[i, 0] = 1  2   2  4   4   4   4   2  6   6    
dp[i, 1] = 1  1   3  3   3   3   5   5  3   7
           ^  ^   ^  ^
           |  |   |  -- gives us the sequence {1, 17, 5, 10}
           |  |   -- dp[2, 1] = dp[1, 0] + 1 because 5 - 17 < 0.
           |  ---- dp[1, 0] = max(dp[0, 1] + 1, 1) = 2 because 17 - 1 > 0
     1 element
   nothing to do
 the subsequence giving 7 is 1, 17, 5, 10, 5, 16, 8, hope I didn't make any careless
 mistakes in computing the other values)
i=0123456789
a=1 17 5 10 13 15 10 5 16 8
dp[i,0]=1 2 4 4 2 6
dp[i,1]=1133537
^  ^   ^  ^
|| |——给出序列{1,17,5,10}
||--dp[2,1]=dp[1,0]+1,因为5-17<0。
|----dp[1,0]=max(dp[0,1]+1,1)=2,因为17-1>0
1要素
无事可做
给出7的子序列是1,17,5,10,5,16,8,希望我没有犯任何粗心的错误
计算其他值时出错)

然后取两个
dp
数组的最大值。

也有贪婪的方法

取第一个元素,然后找出包含第一个元素的连续序列中的最小或最大元素并选择它

也就是说,如果序列是
1,5,7,9,2,4
,首先选择1,然后选择9,因为9是连续序列
1,5,7,9
中的最大值

以相同的方式继续,然后选择2和5。 使用相同的方法,为示例计算子序列:

1, 17, 5, 10, 13, 15, 10, 5, 16, 8

是:
1,17,5,15,5,16,8

这是一个更简单的解决方案

让原始数组A的长度为n。构建另一个长度为n-1的数组B,长度仅为0s和1s。如果A[i]-A[i+1]>=0,则B[i]=0,否则B[i]=1。这可以在O(n)中完成。现在我们有一个只有0和1的数组,现在的问题是找到交替的连续0和1。0的B中的连续子数组将由其任何一个元素表示。例如: 如果B是=[0,0,0,0,0,1,0,0,0,1,0,1,0,1,0],那么我们可以将B简化为Br,它=[0,1,0,1,0,1,0]在O(n)中,实际上我们只需要找到Br的大小,它可以通过一次迭代完成。我的朋友就是给定问题的答案。所以总的复杂度是O(n)+O(n)=O(n)。 换言之: 保留第一个元素。然后找到序列中单调增长或收缩的部分,并从所有这些序列中保留最后一个元素

更新:您需要在此过程中得出的答案中添加一个,因为您正在计算的是曲折,而不是列表的长度。请注意栅栏柱问题:

def ZigZag(tup):

length=len(tup)
lst=[]
附加(1)
一、追加(2)
如果长度>2:
对于范围内的i(2,长度):
如果(tup[i]-tup[i-1])*(tup[i-1]-tup[i-2])<0:
d=lst[i-1]+1
其他:
d=lst[i-1]
一、附加(d)
返回lst[长度-1]

或者您可以使用贪婪算法

public static int longestZigZag(int[] sequence) {
    if (sequence.length==1) return 1;
    if (sequence.length==2) return 2;
    int[] diff = new int[sequence.length-1];

    for (int i=1;i<sequence.length;i++){
        diff[i-1]=sequence[i]-sequence[i-1];
    }
    int prevsign=sign(diff[0]);
    int count=0;
    if (prevsign!=0)
        count=1;
    for (int i=1;i<diff.length;i++){
        int sign=sign(diff[i]);
        if (prevsign*sign==-1){
            prevsign=sign;
            count++;
        }
    }
    return count+1;
}

public static int sign(int a){
    if (a==0) return 0;
    return a/Math.abs(a);
}
public static int longestZigZag(int[]序列){
if(sequence.length==1)返回1;
if(sequence.length==2)返回2;
int[]diff=新的int[sequence.length-1];
对于(int i=1;i
公共静态int longestZigZag(int[]序列){
int max_seq=0;
if(sequence.length==1){
返回1;
}
if(sequence.length==1){
返回2;
public static int longestZigZag(int[] sequence) {
    if (sequence.length==1) return 1;
    if (sequence.length==2) return 2;
    int[] diff = new int[sequence.length-1];

    for (int i=1;i<sequence.length;i++){
        diff[i-1]=sequence[i]-sequence[i-1];
    }
    int prevsign=sign(diff[0]);
    int count=0;
    if (prevsign!=0)
        count=1;
    for (int i=1;i<diff.length;i++){
        int sign=sign(diff[i]);
        if (prevsign*sign==-1){
            prevsign=sign;
            count++;
        }
    }
    return count+1;
}

public static int sign(int a){
    if (a==0) return 0;
    return a/Math.abs(a);
}
public static int longestZigZag(int[] sequence) {
    int max_seq = 0;

    if (sequence.length == 1) {
        return 1;
    }

    if (sequence.length == 1) {
        return 2;
    }

    int dp[] = new int[sequence.length];

    dp[0] = 1;
    dp[1] = 2;

    for (int i = 2; i < sequence.length; i++) {
        for (int j = i - 1; j > 0; j--) {
            if (((sequence[i] > sequence[j] &&
                sequence[j] < sequence[j - 1]) || 
                (sequence[i] < sequence[j] &&
                sequence[j] > sequence[j - 1])) &&
                dp[i] < dp[j] + 1) {
                dp[i] = dp[j] + 1;

                if (dp[i] > max_seq) {
                    max_seq = dp[i];
                }
            } 
        }
    }

    return max_seq;
}
def zigzag(xs):
    res = xs[:2]
    for x in xs[2:]:
        if cmp(res[-1], x) == cmp(res[-1], res[-2]):
            res.append(x)
        else:
            res[-1] = x
    return res
    positive_end_seq[i] = negative_end_seq[i-1];
    negative_end_seq[i] = positive_end_seq[i-1];
    if (A[i-1] > A[i]) { // next element for positive_end_seq
       positive_end_seq[i] += 1; 
    }
    if (A[i-1] < A[i]) { // next element for negqtive_end_seq
       negative_end_seq[i] += 1;
    }
    // if (A[i-1] == A[i]) values don't change
    public static int subZigZag(int[] arr) {
      int pos_count = 1;
      int neg_count = 1;
      for(int i = 1; i < arr.length; ++i) {
        if (arr[i-1] < arr[i]) {
          pos_count = neg_count + 1;
        }
        if (arr[i-1] > arr[i]) {
          neg_count = pos_count+1;
        }
      }
      return Math.max(pos_count, neg_count);
    } 
public static int longestZigZag(int[] sequence) {
    if (sequence == null) {
        return 0;
    }

    int len  = sequence.length;
    if (len <= 2) {
        return len;
    }
    int minima = sequence[0];
    int maxima = sequence[0];
    int maximalen = 1;
    int minimalen = 1;

    for (int i = 1; i < len; i++) {
        if (sequence[i] < maxima) {
            if (minimalen < maximalen + 1) {
                minimalen = maximalen + 1;
                minima = sequence[i];
            } else if (minimalen == maximalen + 1 && sequence[i] < minima) {
                minima = sequence[i];
            }
        }
        if (sequence[i] > minima) {
            if (maximalen < minimalen + 1) {
                maximalen = minimalen + 1;
                maxima = sequence[i];
            } else if (maximalen == minimalen + 1 && sequence[i] > maxima) {
                maxima = sequence[i];
            }
        }
    }

    return Math.max(maximalen, minimalen);
}
vector<int> longest_oscilating_subsequence(const vector<int> seq) {
    vector<int> result; // the resulting subsequence 

    for (int i = 0; i < seq.size(); ++i) {
        if (i > 0 && seq[i] == seq[i - 1]) continue;

        // is this point a local extreme 
        bool local_max = true, local_min = true;
        if (i > 0) {
            local_max = local_max && (seq[i] >= seq[i - 1]);
            local_min = local_min && (seq[i] <= seq[i - 1]);
        }
        if (i < seq.size() - 1) {
            local_max = local_max && (seq[i] >= seq[i + 1]);
            local_min = local_min && (seq[i] <= seq[i + 1]);
        }

        // potentially add it to the sequence 
        if (local_max || local_min) result.push_back(seq[i]);
    }

    return result; 
}
List<Integer> list= new ArrayList<>();
int max = 0;
if(a.length==0 || a.length==1) return 0;
if(a.length==2) return 1;
for(int i=1;i<a.length-1;i++){

    if((a[i-1]<a[i] && a[i+1]<a[i]) || (a[i-1]>a[i] && a[i+1]>a[i])){
        if(list.isEmpty()){
           list.add(a[i-1]); 
        }
        list.add(a[i]);

    }else{
        list.add(a[i+1]); 
        max = Math.max(max,list.size());
        list.clear();
    }

}
return max;