Smallest subsequence with sum of absolute difference of consecutive elements maximized

Given an array arr[] of length N, containing values in the range [1, N], the task is to find a subsequence s1, s2, …, sk such that
\\ Sum = \mid s1 - s2 \mid + \mid s2 - s3 \mid +  ...  +  \mid s_{k-1} - s_{k} \mid
is maximised. In case of multiple subsequences having maximum possible sum, print the smallest one.

Input: N = 3, P = {3, 2, 1}
Output: K = 2, S = {3, 1}
Explanation:
Maximum sum possible = 2
Subsequences {3, 2, 1} and {3, 1} achieves that sum.
Hence, the subsequence {3, 1} is considered being of smaller length.

Input: N = 4, P = {1, 3, 4, 2}
Output: K = 3, S = {1, 4, 2}
Explanation:
Maximum sum possible = 5
Subsequences {1, 3, 4, 2} and {1, 4, 2} achieves that sum.
Hence, the subsequence {1, 4, 2} is considered being of smaller length.

Naive Approach:
Generate all subsequences of length >= 2 and calculate their respective sums. Keep track of the maximum sum obtained for any subsequence. In the case of multiple subsequences having the maximum sum, keep updating the minimum length, and maintain that subsequence. Finally print the subsequence.
Time Complexity: O(2N)

Efficient Approach:
There are a few key observations that will help us proceed:



  1. The maximum sum will be obtained when all the elements in the permutation are considered.
    For example:

    N = 4, P = [1, 3, 4, 2]
    Max sum = | 1 – 3 | + | 3 – 4 | + | 4 – 2 | = 2 + 1 + 2 = 5
    Here, the length is N and the required subsequence is permutation P itself.

    Now that we know the maximum possible sum, the objective is to minimize the subsequence length without affecting this maximum sum.

  2. For a monotonically increasing or decreasing subsequence, maximum sum can be acheived by only considering the First and Last element, for example:

    S = [1, 3, 5, 7]
    Max sum = | 1 – 3 | + | 3 – 5 | + | 5 – 7 | = 2 + 2 + 2 = 6, K = 4
    Considering only first and last element,
    S = [1, 7]
    Max sum = | 1 – 7 | = 6, K = 2

In this way, the length of the subsequence can be reduced without affecting the Max sum.

Hence, from the given array, keep extracting the end-points of monotonically increasing or decreasing subsequences, and add them to the subsequence in the following way:

  • The first and the last element of the permutation are default endpoints
  • An element P[ i ] is a monotonically increasing endpoint if P[ i – 1 ] < P[ i ] > P[ i + 1 ]
  • An element P[ i ] is monotonically decreasing endpoint if P[ i – 1 ] > P[ i ] < P[ i + 1 ]
  • The subsequence thus obtained will have maximum sum and minimum length.

    Below is the implementation of the above approach:

    C++

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // C++ program to find
    // smallest subsequence
    // with sum of absolute
    // difference of consecutive
    // elements maximized
    #include <bits/stdc++.h>
    using namespace std;
      
    // Function to print the smallest
    // subsequence and its sum
    void getSubsequence(vector<int>& arr,
                        int n)
    {
        // Final subsequence
        vector<int> req;
      
        // First element is
        // a default endpoint
        req.push_back(arr[0]);
      
        // Iterating through the array
        for (int i = 1; i < n - 1; i++) {
      
            // Check for monotonically
            // increasing endpoint
            if (arr[i] > arr[i + 1]
                && arr[i] > arr[i - 1])
                req.push_back(arr[i]);
      
            // Check for monotonically
            // decreasing endpoint
            else if (arr[i] < arr[i + 1]
                     && arr[i] < arr[i - 1])
                req.push_back(arr[i]);
        }
      
        // Last element is
        // a default endpoint
        req.push_back(arr[n - 1]);
      
        // Length of final subsequence
        cout << req.size() << endl;
      
        // Print the subsequence
        for (auto x : req)
            cout << x << " ";
    }
      
    // Driver Program
    int main()
    {
        vector<int> arr = { 1, 2, 5, 3,
                            6, 7, 4 };
        int n = arr.size();
        getSubsequence(arr, n);
      
        return 0;
    }

    chevron_right

    
    

    Java

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // Java program to find smallest
    // subsequence with sum of absolute
    // difference of consecutive
    // elements maximized
    import java.util.*;
      
    class GFG{
      
    // Function to print the smallest
    // subsequence and its sum
    static void getSubsequence(int []arr, int n)
    {
          
        // Final subsequence
        Vector<Integer> req = new Vector<Integer>();
      
        // First element is
        // a default endpoint
        req.add(arr[0]);
      
        // Iterating through the array
        for(int i = 1; i < n - 1; i++)
        {
              
           // Check for monotonically
           // increasing endpoint
           if (arr[i] > arr[i + 1] && 
               arr[i] > arr[i - 1])
               req.add(arr[i]);
                 
           // Check for monotonically
           // decreasing endpoint
           else if (arr[i] < arr[i + 1] && 
                    arr[i] < arr[i - 1])
               req.add(arr[i]);
        }
      
        // Last element is
        // a default endpoint
        req.add(arr[n - 1]);
      
        // Length of final subsequence
        System.out.print(req.size() + "\n");
      
        // Print the subsequence
        for(int x : req)
           System.out.print(x + " ");
    }
      
    // Driver code
    public static void main(String[] args)
    {
        int []arr = { 1, 2, 5, 3,
                      6, 7, 4 };
        int n = arr.length;
          
        getSubsequence(arr, n);
    }
    }
      
    // This code is contributed by Amit Katiyar

    chevron_right

    
    

    Python3

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    # Python3 program to find smallest
    # subsequence with sum of absolute
    # difference of consecutive
    # elements maximized
      
    # Function to print the smallest
    # subsequence and its sum
    def getSubsequence(arr, n):
          
        # Final subsequence
        req = []
          
        # First element is
        # a default endpoint
        req.append(arr[0])
          
        # Iterating through the array
        for i in range(1, n - 1):
              
            # Check for monotonically
            # increasing endpoint
            if (arr[i] > arr[i + 1] and
                arr[i] > arr[i - 1]):
                req.append(arr[i])
             
            # Check for monotonically
            # decreasing endpoint
            elif (arr[i] < arr[i + 1] and 
                  arr[i] < arr[i - 1]):
                req.append(arr[i]);
                  
        # Last element is
        # a default endpoint
        req.append(arr[n - 1]);
      
        # Length of final subsequence
        print(len(req))
      
        # Print the subsequence
        for x in req:
            print(x, end = ' ')
      
    # Driver code
    if __name__=='__main__':
          
        arr = [ 1, 2, 5, 3, 6, 7, 4 ]
        n = len(arr)
          
        getSubsequence(arr, n)
      
    # This code is contributed by rutvik_56

    chevron_right

    
    

    C#

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // C# program to find smallest
    // subsequence with sum of absolute
    // difference of consecutive
    // elements maximized
    using System;
    using System.Collections.Generic;
      
    class GFG{
       
    // Function to print the smallest
    // subsequence and its sum
    static void getSubsequence(int []arr, int n)
    {
           
        // Final subsequence
        List<int> req = new List<int>();
       
        // First element is
        // a default endpoint
        req.Add(arr[0]);
       
        // Iterating through the array
        for(int i = 1; i < n - 1; i++)
        {
               
           // Check for monotonically
           // increasing endpoint
           if (arr[i] > arr[i + 1] && 
               arr[i] > arr[i - 1])
               req.Add(arr[i]);
                  
           // Check for monotonically
           // decreasing endpoint
           else if (arr[i] < arr[i + 1] && 
                    arr[i] < arr[i - 1])
               req.Add(arr[i]);
        }
       
        // Last element is
        // a default endpoint
        req.Add(arr[n - 1]);
       
        // Length of readonly subsequence
        Console.Write(req.Count + "\n");
       
        // Print the subsequence
        foreach(int x in req)
           Console.Write(x + " ");
    }
       
    // Driver code
    public static void Main(String[] args)
    {
        int []arr = { 1, 2, 5, 3,
                      6, 7, 4 };
        int n = arr.Length;
           
        getSubsequence(arr, n);
    }
    }
      
    // This code is contributed by Amit Katiyar

    chevron_right

    
    

    Output:

    5
    1 5 3 7 4
    

    Time complexity: O(N)

    competitive-programming-img




    My Personal Notes arrow_drop_up

    Recommended Posts:


    Check out this Author's contributed articles.

    If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

    Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



    Improved By : amit143katiyar, rutvik_56