Longest Zig-Zag Subsequence

10 Jun, 2021
The longest Zig-Zag subsequence problem is to find length of the longest subsequence of given sequence such that all elements of this are alternating. If a sequence {x1, x2, .. xn} is alternating sequence then its element satisfy one of the following relation : 
  x1 < x2 > x3 < x4 > x5 < .... xn or 
  x1 > x2 < x3 > x4 < x5 > .... xn 
Examples :
Input: arr[] = {1, 5, 4}
Output: 3
The whole arrays is of the form  x1 < x2 > x3 

Input: arr[] = {1, 4, 5}
Output: 2
All subsequences of length 2 are either of the form 
x1 < x2; or x1 > x2

Input: arr[] = {10, 22, 9, 33, 49, 50, 31, 60}
Output: 6
The subsequences {10, 22, 9, 33, 31, 60} or
{10, 22, 9, 49, 31, 60} or {10, 22, 9, 50, 31, 60}
are longest Zig-Zag of length 6.
This problem is an extension of longest increasing subsequence problem, but requires more thinking for finding optimal substructure property in this.We will solve this problem by dynamic Programming method, Let A is given array of length n of integers. We define a 2D array Z[n][2] such that Z[i][0] contains longest Zig-Zag subsequence ending at index i and last element is greater than its previous element and Z[i][1] contains longest Zig-Zag subsequence ending at index i and last element is smaller than its previous element, then we have following recurrence relation between them, 
Z[i][0] = Length of the longest Zig-Zag subsequence 
          ending at index i and last element is greater
          than its previous element
Z[i][1] = Length of the longest Zig-Zag subsequence 
          ending at index i and last element is smaller
          than its previous element

Recursive Formulation:
   Z[i][0] = max (Z[i][0], Z[j][1] + 1); 
             for all j < i and A[j] < A[i] 
   Z[i][1] = max (Z[i][1], Z[j][0] + 1); 
             for all j < i and A[j] > A[i]
The first recurrence relation is based on the fact that, If we are at position i and this element has to bigger than its previous element then for this sequence (upto i) to be bigger we will try to choose an element j ( < i) such that A[j] < A[i] i.e. A[j] can become A[i]’s previous element and Z[j][1] + 1 is bigger than Z[i][0] then we will update Z[i][0]. Remember we have chosen Z[j][1] + 1 not Z[j][0] + 1 to satisfy alternate property because in Z[j][0] last element is bigger than its previous one and A[i] is greater than A[j] which will break the alternating property if we update. So above fact derives first recurrence relation, similar argument can be made for second recurrence relation also. 
C++
C
Java
Python3
C#
PHP
Javascript
// C++ program to find longest Zig-Zag subsequence in// an array#include <bits/stdc++.h>using namespace std; // function to return max of two numbersint max(int a, int b) {  return (a > b) ? a : b; } // Function to return longest Zig-Zag subsequence lengthint zzis(int arr[], int n){       /*Z[i][0] = Length of the longest Zig-Zag subsequence          ending at index i and last element is greater          than its previous element     Z[i][1] = Length of the longest Zig-Zag subsequence          ending at index i and last element is smaller          than its previous element   */    int Z[n][2];     /* Initialize all values from 1  */    for (int i = 0; i < n; i++)        Z[i][0] = Z[i][1] = 1;     int res = 1; // Initialize result     /* Compute values in bottom up manner */    for (int i = 1; i < n; i++)    {        // Consider all elements as previous of arr[i]        for (int j = 0; j < i; j++)        {            // If arr[i] is greater, then check with Z[j][1]            if (arr[j] < arr[i] && Z[i][0] < Z[j][1] + 1)                Z[i][0] = Z[j][1] + 1;             // If arr[i] is smaller, then check with Z[j][0]            if( arr[j] > arr[i] && Z[i][1] < Z[j][0] + 1)                Z[i][1] = Z[j][0] + 1;        }         /* Pick maximum of both values at index i  */        if (res < max(Z[i][0], Z[i][1]))            res = max(Z[i][0], Z[i][1]);    }     return res;} /* Driver program */int main(){    int arr[] = { 10, 22, 9, 33, 49, 50, 31, 60 };    int n = sizeof(arr)/sizeof(arr[0]);    cout<<"Length of Longest Zig-Zag subsequence is "<<zzis(arr, n)<<endl;    return 0;} // This code is contributed by noob2000.
// C program to find longest Zig-Zag subsequence in// an array#include <stdio.h>#include <stdlib.h> // function to return max of two numbersint max(int a, int b) {  return (a > b) ? a : b; } // Function to return longest Zig-Zag subsequence lengthint zzis(int arr[], int n){    /*Z[i][0] = Length of the longest Zig-Zag subsequence          ending at index i and last element is greater          than its previous element     Z[i][1] = Length of the longest Zig-Zag subsequence          ending at index i and last element is smaller          than its previous element   */    int Z[n][2];     /* Initialize all values from 1  */    for (int i = 0; i < n; i++)        Z[i][0] = Z[i][1] = 1;     int res = 1; // Initialize result     /* Compute values in bottom up manner */    for (int i = 1; i < n; i++)    {        // Consider all elements as previous of arr[i]        for (int j = 0; j < i; j++)        {            // If arr[i] is greater, then check with Z[j][1]            if (arr[j] < arr[i] && Z[i][0] < Z[j][1] + 1)                Z[i][0] = Z[j][1] + 1;             // If arr[i] is smaller, then check with Z[j][0]            if( arr[j] > arr[i] && Z[i][1] < Z[j][0] + 1)                Z[i][1] = Z[j][0] + 1;        }         /* Pick maximum of both values at index i  */        if (res < max(Z[i][0], Z[i][1]))            res = max(Z[i][0], Z[i][1]);    }     return res;} /* Driver program */int main(){    int arr[] = { 10, 22, 9, 33, 49, 50, 31, 60 };    int n = sizeof(arr)/sizeof(arr[0]);    printf("Length of Longest Zig-Zag subsequence is %d\n",            zzis(arr, n) );    return 0;}
// Java program to find longest// Zig-Zag subsequence in an arrayimport java.io.*; class GFG { // Function to return longest// Zig-Zag subsequence lengthstatic int zzis(int arr[], int n){    /*Z[i][0] = Length of the longest        Zig-Zag subsequence ending at        index i and last element is        greater than its previous element    Z[i][1] = Length of the longest        Zig-Zag subsequence ending at        index i and last element is        smaller than its previous        element */    int Z[][] = new int[n][2];     /* Initialize all values from 1 */    for (int i = 0; i < n; i++)        Z[i][0] = Z[i][1] = 1;     int res = 1; // Initialize result     /* Compute values in bottom up manner */    for (int i = 1; i < n; i++)    {        // Consider all elements as        // previous of arr[i]        for (int j = 0; j < i; j++)        {            // If arr[i] is greater, then            // check with Z[j][1]            if (arr[j] < arr[i] &&                Z[i][0] < Z[j][1] + 1)                Z[i][0] = Z[j][1] + 1;             // If arr[i] is smaller, then            // check with Z[j][0]            if( arr[j] > arr[i] &&              Z[i][1] < Z[j][0] + 1)                Z[i][1] = Z[j][0] + 1;        }         /* Pick maximum of both values at        index i */        if (res < Math.max(Z[i][0], Z[i][1]))            res = Math.max(Z[i][0], Z[i][1]);    }     return res;} /* Driver program */public static void main(String[] args){    int arr[] = { 10, 22, 9, 33, 49,                  50, 31, 60 };    int n = arr.length;    System.out.println("Length of Longest "+                    "Zig-Zag subsequence is " +                    zzis(arr, n));}}// This code is contributed by Prerna Saini
# Python3 program to find longest# Zig-Zag subsequence in an array # Function to return max of two numbers # Function to return longest# Zig-Zag subsequence lengthdef zzis(arr, n):         '''Z[i][0] = Length of the longest Zig-Zag subsequence        ending at index i and last element is greater        than its previous element    Z[i][1] = Length of the longest Zig-Zag subsequence        ending at index i and last element is smaller        than its previous element '''    Z = [[1 for i in range(2)] for i in range(n)]      res = 1 # Initialize result     # Compute values in bottom up manner '''    for i in range(1, n):                 # Consider all elements as previous of arr[i]        for j in range(i):             # If arr[i] is greater, then check with Z[j][1]            if (arr[j] < arr[i] and Z[i][0] < Z[j][1] + 1):                Z[i][0] = Z[j][1] + 1             # If arr[i] is smaller, then check with Z[j][0]            if( arr[j] > arr[i] and Z[i][1] < Z[j][0] + 1):                Z[i][1] = Z[j][0] + 1         # Pick maximum of both values at index i '''        if (res < max(Z[i][0], Z[i][1])):            res = max(Z[i][0], Z[i][1])     return res # Driver Codearr = [10, 22, 9, 33, 49, 50, 31, 60]n = len(arr)print("Length of Longest Zig-Zag subsequence is",                                    zzis(arr, n)) # This code is contributed by Mohit Kumar
// C# program to find longest// Zig-Zag subsequence in an arrayusing System; class GFG{     // Function to return longest// Zig-Zag subsequence lengthstatic int zzis(int []arr, int n){    /*Z[i][0] = Length of the longest        Zig-Zag subsequence ending at        index i and last element is        greater than its previous element    Z[i][1] = Length of the longest        Zig-Zag subsequence ending at        index i and last element is        smaller than its previous        element */    int [,]Z = new int[n, 2];     /* Initialize all values from 1 */    for (int i = 0; i < n; i++)        Z[i, 0] = Z[i, 1] = 1;     // Initialize result    int res = 1;     /* Compute values in    bottom up manner */    for (int i = 1; i < n; i++)    {        // Consider all elements as        // previous of arr[i]        for (int j = 0; j < i; j++)        {            // If arr[i] is greater, then            // check with Z[j][1]            if (arr[j] < arr[i] &&                Z[i, 0] < Z[j, 1] + 1)                Z[i, 0] = Z[j, 1] + 1;                             // If arr[i] is smaller, then            // check with Z[j][0]            if( arr[j] > arr[i] &&            Z[i, 1] < Z[j, 0] + 1)                Z[i, 1] = Z[j, 0] + 1;        }         /* Pick maximum of both values at        index i */        if (res < Math.Max(Z[i, 0], Z[i, 1]))            res = Math.Max(Z[i, 0], Z[i, 1]);    }     return res;} // Driver Codestatic public void Main (){    int []arr = {10, 22, 9, 33,                 49, 50, 31, 60};    int n = arr.Length;    Console.WriteLine("Length of Longest "+                      "Zig-Zag subsequence is " +                                   zzis(arr, n));    }} // This code is contributed by ajit
<?php//PHP program to find longest Zig-Zag//subsequence in  an array // function to return max of two numbersfunction  maxD($a, $b) {    return ($a > $b) ? $a : $b;    } // Function to return longest Zig-Zag subsequence lengthfunction  zzis($arr, $n){    /*Z[i][0] = Length of the longest Zig-Zag subsequence        ending at index i and last element is greater        than its previous element    Z[i][1] = Length of the longest Zig-Zag subsequence        ending at index i and last element is smaller        than its previous element */     //$Z[$n][2];     /* Initialize all values from 1 */    for ($i = 0; $i < $n; $i++)        $Z[$i][0] = $Z[$i][1] = 1;      $res = 1; // Initialize result     /* Compute values in bottom up manner */    for ($i = 1; $i < $n; $i++)    {        // Consider all elements as previous of arr[i]        for ($j = 0; $j < $i; $j++)        {            // If arr[i] is greater, then check with Z[j][1]            if ($arr[$j] < $arr[$i] && $Z[$i][0] < $Z[$j][1] + 1)                $Z[$i][0] = $Z[$j][1] + 1;             // If arr[i] is smaller, then check with Z[j][0]            if( $arr[$j] > $arr[$i] && $Z[$i][1] < $Z[$j][0] + 1)                $Z[$i][1] = $Z[$j][0] + 1;        }         /* Pick maximum of both values at index i */        if ($res < max($Z[$i][0], $Z[$i][1]))            $res = max($Z[$i][0], $Z[$i][1]);    }     return $res;} /* Driver program */      $arr = array( 10, 22, 9, 33, 49, 50, 31, 60 );    $n = sizeof($arr);    echo "Length of Longest Zig-Zag subsequence is ",            zzis($arr, $n) ;    echo "\n";   #This code is contributed by aj_36?>
<script>     // Javascript program to find longest    // Zig-Zag subsequence in an array         // Function to return longest    // Zig-Zag subsequence length    function zzis(arr, n)    {        /*Z[i][0] = Length of the longest            Zig-Zag subsequence ending at            index i and last element is            greater than its previous element        Z[i][1] = Length of the longest            Zig-Zag subsequence ending at            index i and last element is            smaller than its previous            element */        let Z = new Array(n);                 for(let i = 0; i < n; i++)        {            Z[i] = new Array(2);        }         /* Initialize all values from 1 */        for (let i = 0; i < n; i++)            Z[i][0] = Z[i][1] = 1;         let res = 1; // Initialize result         /* Compute values in bottom up manner */        for (let i = 1; i < n; i++)        {            // Consider all elements as            // previous of arr[i]            for (let j = 0; j < i; j++)            {                // If arr[i] is greater, then                // check with Z[j][1]                if (arr[j] < arr[i] &&                    Z[i][0] < Z[j][1] + 1)                    Z[i][0] = Z[j][1] + 1;                 // If arr[i] is smaller, then                // check with Z[j][0]                if( arr[j] > arr[i] &&                  Z[i][1] < Z[j][0] + 1)                    Z[i][1] = Z[j][0] + 1;            }             /* Pick maximum of both values at            index i */            if (res < Math.max(Z[i][0], Z[i][1]))                res = Math.max(Z[i][0], Z[i][1]);        }         return res;    }         let arr = [ 10, 22, 9, 33, 49, 50, 31, 60 ];    let n = arr.length;    document.write("Length of Longest "+ "Zig-Zag subsequence is " + zzis(arr, n));                     </script>
Output : 
Length of Longest Zig-Zag subsequence is 6
Time Complexity : O(n2) Auxiliary Space : O(n)A better approach with time complexity O(n) is explained below: Let the sequence be stored in an unsorted integer array arr[N]. We shall proceed by comparing the mathematical signs(negative or positive) of the difference of two consecutive elements of arr. To achieve this, we shall store the sign of (arr[i] – arr[i-1]) in a variable, subsequently comparing it with that of (arr[i+1] – arr[i]). If it is different, we shall increment our result. For checking the sign, we shall use a simple Signum Function, which shall determine the sign of a number passed to it. That is, Considering the fact that we traverse the sequence only once, this becomes an O(n) solution.The algorithm for the approach discussed above is : 
Input integer array seq[N].
Initialize integer lastSign to 0. 
FOR i in range 1 to N - 1
    integer sign = signum(seq[i] - seq[i-1])
    IF sign != lastSign AND IF sign != 0
        increment length by 1. lastSign = sign.
    END IF
END FOR
return length.
Following is the implementation of the above approach: 
C++
Java
Python3
C#
Javascript
/*CPP program to find the maximum length of zig-zagsub-sequence in given sequence*/#include <bits/stdc++.h>#include <iostream>using namespace std; // Function prototype.int signum(int n); /* Function to calculate maximum length of zig-zagsub-sequence in given sequence.*/int maxZigZag(int seq[], int n){    if (n == 0) {        return 0;    }     int lastSign = 0, length = 1;       // Length is initialized to 1 as    // that is minimum value    // for arbitrary sequence.    for (int i = 1; i < n; ++i) {        int Sign = signum(seq[i] - seq[i - 1]);         // It qualifies        if (Sign != lastSign && Sign != 0)        {                       // Updating lastSign            lastSign = Sign;            length++;        }    }    return length;} /* Signum function :Returns 1 when passed a positive integerReturns -1 when passed a negative integerReturns 0 when passed 0. */int signum(int n){    if (n != 0) {        return n > 0 ? 1 : -1;    }     else {        return 0;    }}// Driver methodint main(){    int sequence1[4] = { 1, 3, 6, 2 };    int sequence2[5] = { 5, 0, 3, 1, 0 };     int n1 = sizeof(sequence1)             / sizeof(*sequence1); // size of sequences    int n2 = sizeof(sequence2) / sizeof(*sequence2);     int maxLength1 = maxZigZag(sequence1, n1);    int maxLength2        = maxZigZag(sequence2, n2); // function call     cout << "The maximum length of zig-zag sub-sequence in "            "first sequence is: "         << maxLength1;    cout << endl;    cout << "The maximum length of zig-zag sub-sequence in "            "second sequence is: "         << maxLength2;}
// Java code to find out maximum length of zig-zag// sub-sequence in given sequenceclass zigZagMaxLength {    // Driver method    public static void main(String[] args)    {        int[] sequence1 = { 1, 3, 6, 2 };        int[] sequence2 = { 5, 0, 3, 1, 0 };         int n1 = sequence1.length; // size of sequences        int n2 = sequence2.length;         int maxLength1 = maxZigZag(sequence1, n1);        int maxLength2            = maxZigZag(sequence2, n2); // function call         System.out.println(            "The maximum length of zig-zag sub-sequence in first sequence is: "            + maxLength1);        System.out.println(            "The maximum length of zig-zag sub-sequence in second sequence is: "            + maxLength2);    }     /* Function to calculate maximum length of zig-zag    sub-sequence in given sequence.    */     static int maxZigZag(int[] seq, int n)    {        if (n == 0) {            return 0;        }         int lastSign = 0, length = 1;        // length is initialized to 1 as that is minimum        // value for arbitrary sequence.         for (int i = 1; i < n; ++i) {            int Sign = signum(seq[i] - seq[i - 1]);             if (Sign != 0                && Sign != lastSign) // it qualifies            {                lastSign = Sign; // updating lastSign                length++;            }        }         return length;    }     /* Signum function :    Returns 1 when passed a positive integer    Returns -1 when passed a negative integer    Returns 0 when passed 0. */    static int signum(int n)    {        if (n != 0) {            return n > 0 ? 1 : -1;        }         else {            return 0;        }    }}
# Python3 program to find the maximum# length of zig-zag sub-sequence in# given sequence # Function to calculate maximum length# of zig-zag sub-sequence in given sequence.  def maxZigZag(seq, n):     if (n == 0):        return 0     lastSign = 0     # Length is initialized to 1 as that is    # minimum value for arbitrary sequence    length = 1     for i in range(1, n):        Sign = signum(seq[i] - seq[i - 1])         # It qualifies        if (Sign != lastSign and Sign != 0):             # Updating lastSign            lastSign = Sign            length += 1     return length # Signum function :# Returns 1 when passed a positive integer# Returns -1 when passed a negative integer# Returns 0 when passed 0.  def signum(n):     if (n != 0):        return 1 if n > 0 else -1    else:        return 0  # Driver codeif __name__ == '__main__':     sequence1 = [1, 3, 6, 2]    sequence2 = [5, 0, 3, 1, 0]     n1 = len(sequence1)    n2 = len(sequence2)     # Function call    maxLength1 = maxZigZag(sequence1, n1)    maxLength2 = maxZigZag(sequence2, n2)     print("The maximum length of zig-zag sub-sequence "          "in first sequence is:", maxLength1)    print("The maximum length of zig-zag sub-sequence "          "in second sequence is:", maxLength2) # This code is contributed by himanshu77
// C# code to find out maximum length of// zig-zag sub-sequence in given sequenceusing System; class zigZagMaxLength {    // Driver method    public static void Main(String[] args)    {        int[] sequence1 = { 1, 3, 6, 2 };        int[] sequence2 = { 5, 0, 3, 1, 0 };         int n1 = sequence1.Length; // size of sequences        int n2 = sequence2.Length;         int maxLength1 = maxZigZag(sequence1, n1);        int maxLength2            = maxZigZag(sequence2, n2); // function call         Console.WriteLine(            "The maximum length of zig-zag sub-sequence"            + " in first sequence is: " + maxLength1);        Console.WriteLine(            "The maximum length of zig-zag "            + "sub-sequence in second sequence is: "            + maxLength2);    }     /* Function to calculate maximum length of zig-zag    sub-sequence in given sequence.    */    static int maxZigZag(int[] seq, int n)    {        if (n == 0) {            return 0;        }         // length is initialized to 1 as that is minimum        // value for arbitrary sequence.        int lastSign = 0, length = 1;         for (int i = 1; i < n; ++i) {            int Sign = signum(seq[i] - seq[i - 1]);             if (Sign != 0                && Sign != lastSign) // it qualifies            {                lastSign = Sign; // updating lastSign                length++;            }        }         return length;    }     /* Signum function :    Returns 1 when passed a positive integer    Returns -1 when passed a negative integer    Returns 0 when passed 0. */    static int signum(int n)    {        if (n != 0) {            return n > 0 ? 1 : -1;        }         else {            return 0;        }    }} // This code is contributed by Rajput-Ji
<script>     // Javascript code to find out maximum length of    // zig-zag sub-sequence in given sequence         /* Function to calculate maximum length of zig-zag    sub-sequence in given sequence.    */    function maxZigZag(seq, n)    {        if (n == 0) {            return 0;        }          // length is initialized to 1 as that is minimum        // value for arbitrary sequence.        let lastSign = 0, length = 1;          for (let i = 1; i < n; ++i) {            let Sign = signum(seq[i] - seq[i - 1]);              if (Sign != 0 && Sign != lastSign) // it qualifies            {                lastSign = Sign; // updating lastSign                length++;            }        }          return length;    }         /* Signum function :    Returns 1 when passed a positive integer    Returns -1 when passed a negative integer    Returns 0 when passed 0. */    function signum(n)    {        if (n != 0) {            return n > 0 ? 1 : -1;        }          else {            return 0;        }    }         let sequence1 = [ 1, 3, 6, 2 ];    let sequence2 = [ 5, 0, 3, 1, 0 ];     let n1 = sequence1.length; // size of sequences    let n2 = sequence2.length;     let maxLength1 = maxZigZag(sequence1, n1);    let maxLength2 = maxZigZag(sequence2, n2); // function call     document.write("The maximum length of zig-zag sub-sequence"      + " in first sequence is: " + maxLength1 + "</br>");    document.write(      "The maximum length of zig-zag "      + "sub-sequence in second sequence is: "      + maxLength2 + "</br>");       </script>
Output : 
The maximum length of zig-zag sub-sequence in first sequence is: 3
The maximum length of zig-zag sub-sequence in second sequence is: 4
Time Complexity : O(n) Auxiliary Space : O(1)This article is contributed by Utkarsh Trivedi. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above. 
jit_t
santhanambr2002
mohit kumar 29
Rajput-Ji
himanshu77
winter_soldier
rameshtravel07
divyeshrabadiya07
noob2000
Accolite
subsequence
Arrays
Dynamic Programming
Accolite
Arrays
Dynamic Programming
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Maximum and minimum of an array using minimum number of comparisons
Top 50 Array Coding Problems for Interviews
Multidimensional Arrays in Java
Stack Data Structure (Introduction and Program)
Linear Search
Program for Fibonacci numbers
0-1 Knapsack Problem | DP-10
Longest Common Subsequence | DP-4
Longest Palindromic Substring | Set 1
Longest Increasing Subsequence | DP-3