Z字形序列的最大长度

时间:2015-04-02 06:42:27

标签: algorithm

如果整数序列的每个元素严格小于或严格大于其邻居,则称为Z字形序列。

示例:序列4 2 3 1 5 3形成一个之字形,但不是7 3 5 5 2和3 8 6 4 5。

对于给定的整数数组,我们需要找到形成Z字形序列的最大(连续)子阵列的长度。

这可以在O(N)中完成吗?

目前我的解决方案是O(N ^ 2),它只是简单地取每两个点并检查每个可能的子阵列是否满足条件。

7 个答案:

答案 0 :(得分:1)

我声称任何2个Z字形子序列的重叠序列的长度是最多1

矛盾证明:

假设a_i .. a_j是最长的锯齿形子序列,并且还有另一个锯齿形子序列b_m...b_n重叠。

不失一般性,让我们说重叠的部分是

  

a_i ... a_k ... a_j

     

-------- B_M ... b_k” ... B_N

a_k = b_m,a_k + 1 = b_m + 1 ... a_j = b_k'其中k'-m = j-k> 0(至少2个元素重叠)

然后他们可以合并形成一个更长的锯齿形序列,矛盾。

这意味着他们可以相互重叠的唯一情况就像

3 5 3 2 3 2 3

3 5 33 2 3 2 3在1个元素重叠

这仍然可以在O(N)中解决,我相信,就像贪婪地增加之字形长度一样。如果失败,将迭代器1元素移回并将其视为新的曲折起点

记录您找到的最新和最长的锯齿形长度

答案 1 :(得分:0)

对于每个索引i,您可以找到最小的j,使得索引为j,j + 1,...,i-1,i的子阵列为锯齿形。这可以分两个阶段完成:

找到最长的"增加"之字形(以a[1]>a[0]开头):

start = 0
increasing[0] = 0
sign = true
for (int i = 1; i < n; i ++)
  if ((arr[i] > arr[i-1] && sign) || )arr[i] < arr[i-1] && !sign)) {
      increasing[i] = start
      sign = !sign
  } else if (arr[i-1] < arr[i]) { //increasing and started last element
     start = i-1
     sign = false
     increasing[i] = i-1
  } else { //started this element
      start = i
      sign = true
      increasing[i] = i
  }
}

同样做&#34;减少&#34; zig-zag,你可以找到每个索引最早的&#34;一个之字形子阵的可能开始。
从那里,找到最大可能的锯齿形很容易。

由于所有的操作都是在O(n)完成的,而你基本上是一个接一个地完成,这就是你的复杂性。

你可以结合两者&#34;增加&#34;并且&#34;减少&#34;一气呵成:

start = 0
maxZigZagStart[0] = 0
sign = true
for (int i = 1; i < n; i ++)
  if ((arr[i] > arr[i-1] && sign) || )arr[i] < arr[i-1] && !sign)) {
      maxZigZagStart[i] = start
      sign = !sign
  } else if (arr[i-1] > arr[i]) { //decreasing:
     start = i-1
     sign = false
     maxZigZagStart[i] = i-1
  } else if (arr[i-1] < arr[i]) { //increasing:
      start = i-1
      sign = true
      maxZigZagStart[i] = i-1
  } else { //equality
     start = i
     //guess it is increasing, if it is not - will be taken care of next iteration
     sign = true 
     maxZigZagStart[i] = i
  }
}

你可以看到你甚至可以放弃maxZigZagStart辅助数组并存储本地最大长度。

答案 2 :(得分:0)

沿着数组走,看看当前项目是否属于(符合定义)之字形。记住las zigzag start,它是数组的开始或最近的非Z字形元素之后的第一个zigzag元素。这和当前项目定义一些之字形子阵列。当它看起来比之前发现的长时,存储新的最长锯齿形长度。继续直到数组结束,您应该在O(N)中完成任务。

答案 3 :(得分:0)

简单的一次通过算法草图。 Cmp比较相邻元素,为较少,相等和较大的情况返回-1,0,1。 对于Cmp过渡的情况,Zigzag结束:

0 0
-1 0
1 0

Zigzag结束,新系列开始:

0 -1
0 1
-1 -1
1 1

Zigzag系列继续进行过渡

-1 1
1 -1

ALGO:

Start = 0
LastCmp =  - Compare(A[i], A[i - 1]) //prepare to use the first element individually
MaxLen = 0
for i = 1 to N - 1 do
    Cmp = Compare(A[i], A[i - 1])  //returns -1, 0, 1 for less, equal and greater cases
    if Abs(Cmp  - LastCmp) <> 2 then 
        //zigzag condition is violated, series ends, new series starts
        MaxLen = Max(MaxLen, i - 1 - Start)
        Start = i
    //else series continues, nothing to do
    LastCmp = Cmp
//check for ending zigzag
if LastCmp <> 0 then
    MaxLen = Max(MaxLen, N - Start)

输出示例:

2 6 7 1 7 0 7 3 1 1 7 4 
5         (7 1 7 0 7)
8 0 0 3 5 8 
1
0 0 7 0 
2
1 2 0 7 9 
3
8 3 5 2 
4
1 3 7 1 6 6 
2
1 4 0 6 6 3 4 3 8 0 9 9 
5

答案 4 :(得分:0)

抱歉,我使用perl来写这个。

#!/usr/bin/perl

@a = ( 5, 4, 2, 3, 1, 5, 3, 7, 3, 5, 5, 2, 3, 8, 6, 4, 5 );

$n = scalar @a;

$best_start = 0;
$best_end = 1;
$best_length = 2;
$start = 0;
$end = 1;
$direction = ($a[0] > $a[1]) ? 1 : ($a[0] < $a[1]) ? -1 : 0;
for($i=2; $i<$n; $i++) {
    // a trick here, same value make $new_direction = $direction
    $new_direction = ($a[$i-1] > $a[$i]) ? 1 : ($a[$i-1] < $a[$i]) ? -1 : $direction;

    print "$a[$i-1] > $a[$i] : direction $new_direction Vs $direction\n";

    if ($direction != $new_direction) {
        $end = $i;
    } else {
        $this_length = $end - $start + 1;
        if ($this_length > $best_length) {
            $best_start = $start;
            $best_end = $end;
            $best_length = $this_length;
        }
        $start = $i-1;
        $end = $i;
    }
    $direction = $new_direction;
}

$this_length = $end - $start + 1;
if ($this_length > $best_length) {
    $best_start = $start;
    $best_end = $end;
    $best_length = $this_length;
}

print "BEST $best_start to $best_end length $best_length\n";
for ($i=$best_start; $i <= $best_end; $i++) {
    print $a[$i], " ";
}
print "\n";

答案 5 :(得分:0)

让我们以序列5 9 3 4 5 4 2 3 6 5 2 1 3为例。你有一个条件,子序列的每个内部元素都应该满足(元素严格地小于或严格地大于它的邻居)。让我们为整个序列的每个元素计算这个条件:

5 9 3 6 5 7 2 3 6 5 2 1 3
0 1 1 1 1 1 1 0 1 0 0 1 0

最外层元素的条件未定义,因为它们每个只有一个邻居。但为方便起见,我将其定义为0

1的最长子序列(9 3 6 5 7 2)是最长的之字形子序列(5 9 3 6 5 7 2 3)的内部部分。所以算法是:

  1. 找到满足条件的元素的最长子序列。
  2. 向每一方添加一个元素。
  3. 第一步可以通过以下算法在O(n)中完成:

    max_length = 0
    current_length = 0
    for i from 2 to len(a) - 1:
        if a[i - 1] < a[i] > a[i + 1] or a[i - 1] > a[i] < a[i + 1]:
            current_length += 1
        else:
            max_length = max(max_length, current_length)
            current_length = 0
    max_length = max(max_length, current_length)
    

    唯一特殊情况是序列总长度为01。然后整个序列将是最长的之字形子序列。

答案 6 :(得分:0)

#include "iostream" 
using namespace std ;

int main(){

    int t ; scanf("%d",&t) ;

    while(t--){

    int n ; scanf("%d",&n) ;

    int size1 = 1 , size2 = 1 , seq1  , seq2 , x ;
    bool flag1 = true  , flag2 = true ;

    for(int i=1 ; i<=n ; i++){
        scanf("%d",&x) ;

        if( i== 1 )seq1 = seq2 = x ;

        else {

            if( flag1 ){

                if( x>seq1){
                    size1++ ;
                    seq1 = x ;
                    flag1 = !flag1 ;
                }

                else if( x < seq1 )
                    seq1 = x ;
            }

            else{

                if( x<seq1){
                    size1++ ;
                    seq1=x ;
                    flag1 = !flag1 ;
                }

                else if( x > seq1 )
                    seq1 = x ;

            }

            if( flag2  ){

                if( x < seq2 ){
                    size2++ ;
                    seq2=x ;
                    flag2 = !flag2 ;
                }

                else if( x > seq2 )
                    seq2 = x ;

            }

            else {

                if( x > seq2 ){
                    size2++ ;
                    seq2 = x ;
                    flag2 = !flag2 ;
                }

                else if( x < seq2 )
                    seq2 = x ;
            }

        }
    }

    printf("%d\n",max(size1,size2)) ;
    }

    return 0 ;
}