Open In App

Longest subsequence with first and last element greater than all other elements

Last Updated : 29 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a permutation from 1 to N of size N. Find the length of the longest subsequence having the property that the first and last element is greater than all the other subsequence elements. 
Examples: 
 

Input : N = 6 
4 2 6 5 3 1 
Output :
The subsequence that has the longest size is [4, 2, 3] or [4, 2, 6] or [4, 2, 5]. No other subsequence holds the above property with first and last element greater than all remaining subsequence elements.
Input : N = 5 
5 4 1 2 3 
Output :
The longest subsequence is [5, 1, 2, 3] or [4, 1, 2, 3]. With 5 and 3 greater than all other subsequence elements i.e 1 and 2. 
 

Approach: 
Idea is to use Fenwick tree data structure.Start iterating from the highest value in the permutation to lowest one. For each iteration, move left or a right pointer to the current element only if the left pointer can be moved to more left and right pointer to more right. 
If left index is L and right index is R then there are elements from [L+1, R-1] in between. For this particular iteration i, count the number of elements that are lesser than min(arr[L], arr[R]) using the fenwick tree. 
Store each query of type {left+1, right-1, val, index}, where left and right are current left and right pointers and val is the min of arr[L] and arr[R] and idx is the index of that particular query.
 

  1. Sort the array in ascending order.
  2. Sort the queries according to val i.e min(arr[L], arr[R] ) in ascending order, initialize Fenwick array as 0.
  3. Start from the first query and traverse the array until the value in the array is less than equal to val. For each such element update the Fenwick tree with value equal to 1.
  4. Query the Fenwick array in the range l to r.
  5. Print maximum of all the query results .

Below is the implementation of the above approach:
 

CPP




// C++ implementation of the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
struct Query {
 
    int l, r, x, index;
};
 
struct Arrays {
     
    int val, index;
};
 
// Comparison functions
bool cmp1(Query q1, Query q2)
{
    return q1.x < q2.x;
}
 
bool cmp2(Arrays x, Arrays y)
{
    return x.val < y.val;
}
 
// Function to update the value in Fenwick tree
void update(int* Fenwick, int index, int val, int n)
{
    while (index <= n) {
         
        Fenwick[index] += val;
        index += index & (-index);
    }
}
 
// Function to return the query result
int query(int* Fenwick, int index, int n)
{
    int sum = 0;
     
    while (index > 0) {
         
        sum = sum + Fenwick[index];
        index -= index & (-index);
    }
     
    return sum;
}
 
// Function to return the length of subsequence
int maxLength(int n, vector<int>& v)
{
    int where[n + 2];
     
    memset(where, 0, sizeof where);
     
    Arrays arr[n];
 
    // Store the value in struct Array
    for (int i = 1; i <= n; ++i) {
         
        v[i - 1] = v[i - 1] - 1;
         
        int x = v[i - 1];
         
        where[x] = i - 1;
        arr[i - 1].val = x;
        arr[i - 1].index = i - 1;
    }
 
    // If less than 2 elements are
    // present return that element.
    if (n <= 2) {
         
        cout << n << endl;
         
        return 0;
    }
 
    // Set the left and right pointers to extreme
    int left = n, right = 0, mx = 0;
     
    Query queries[4 * n];
     
    int j = 0;
    for (int i = n - 1; i >= 0; --i) {
 
        // Calculate left and right pointer index.
        left = min(left, where[i]);
        right = max(right, where[i]);
         
        int diff = right - left;
         
        if (diff == 0 || diff == 1) {
            continue;
        }
         
        int val1 = v[left];
        int val2 = v[right];
        int minn = min(val1, val2);
 
        // Store the queries from [L+1, R-1].
        queries[j].l = left + 1;
        queries[j].r = right - 1;
        queries[j].x = minn;
        queries[j].index = j;
         
        ++j;
    }
 
    int Fenwick[n + 1];
     
    memset(Fenwick, 0, sizeof Fenwick);
     
    int q = j - 1;
 
    // Sort array and queries for fenwick updates
    sort(arr, arr + n + 1, cmp2);
    sort(queries, queries + q + 1, cmp1);
     
    int curr = 0;
    int ans[q];
    memset(ans, 0, sizeof ans);
 
    // For each query calculate maxx for
    // the answer and store it in ans array.
    for (int i = 0; i <= q; ++i) {
 
        while (arr[curr].val <= queries[i].x and curr < n) {
             
            update(Fenwick, arr[curr].index + 1, 1, n);
            curr++;
        }
 
        ans[queries[i].index] =
                query(Fenwick, queries[i].r + 1, n)
                - query(Fenwick, queries[i].l, n);
    }
     
    for (int i = 0; i <= q; ++i) {
        mx = max(mx, ans[i]);
    }
     
    // Mx will be mx + 2 as while calculating
    // mx, we excluded element
    // at index left and right
    mx = mx + 2;
    return mx;
}
 
// Driver Code
int main()
{
    int n = 6;
    vector<int> v = { 4, 2, 6, 5, 3, 1 };
 
    cout << maxLength(n, v) << endl;
     
    return 0;
}


Java




import java.util.*;
 
public class GFG {
    static class Query {
        int l, r, x, index;
    }
 
    static class ArrayElement {
        int val, index;
    }
 
    // Comparison functions
    static boolean cmp1(Query q1, Query q2) {
        return q1.x < q2.x;
    }
 
    static boolean cmp2(ArrayElement x, ArrayElement y) {
        return x.val < y.val;
    }
 
    // Function to update the value in Fenwick tree
    static void update(int[] Fenwick, int index, int val, int n) {
        while (index <= n) {
            Fenwick[index] += val;
            index += index & (-index);
        }
    }
 
    // Function to return the query result
    static int query(int[] Fenwick, int index, int n) {
        int sum = 0;
        while (index > 0) {
            sum = sum + Fenwick[index];
            index -= index & (-index);
        }
        return sum;
    }
 
    // Function to return the length of subsequence
    static int maxLength(int n, ArrayList<Integer> v) {
        int[] where = new int[n + 2];
        ArrayElement[] arr = new ArrayElement[n];
 
        Query[] queries = new Query[4 * n];
 
        Query[] ans = new Query[n];
 
        for (int i = 1; i <= n; ++i) {
            v.set(i - 1, v.get(i - 1) - 1);
            int x = v.get(i - 1);
            where[x] = i - 1;
            arr[i - 1] = new ArrayElement();
            arr[i - 1].val = x;
            arr[i - 1].index = i - 1;
        }
 
        if (n <= 2) {
            System.out.println(n);
            return 0;
        }
 
        int left = n, right = 0, mx = 0;
 
        int j = 0;
        for (int i = n - 1; i >= 0; --i) {
            left = Math.min(left, where[i]);
            right = Math.max(right, where[i]);
            int diff = right - left;
            if (diff == 0 || diff == 1) {
                continue;
            }
            int val1 = v.get(left);
            int val2 = v.get(right);
            int minn = Math.min(val1, val2);
 
            queries[j] = new Query();
            queries[j].x = minn;
            queries[j].index = j;
            queries[j].l = left + 1;
            queries[j].r = right - 1;
 
            ++j;
        }
 
        int[] Fenwick = new int[n + 1];
        int q = j - 1;
 
        ArrayElement[] sortedArr = Arrays.copyOfRange(arr, 0, n + 1);
        Query[] sortedQueries = Arrays.copyOfRange(queries, 0, q + 1);
 
        Query[] sortedAns = new Query[n];
 
        int curr = 0;
        Query[] sortedAnsTemp = Arrays.copyOfRange(sortedAns, 0, n);
 
          // For each query calculate maxx for
        // the answer and store it in ans array.
        for (int i = 0; i <= q; ++i) {
            while (sortedArr[curr].val <= sortedQueries[i].x && curr < n) {
                update(Fenwick, sortedArr[curr].index + 1, 1, n);
                curr++;
            }
            sortedAnsTemp[sortedQueries[i].index] = new Query();
            sortedAnsTemp[sortedQueries[i].index].x = query(Fenwick, sortedQueries[i].r + 1, n) - query(Fenwick, sortedQueries[i].l, n);
            sortedAnsTemp[sortedQueries[i].index].index = sortedQueries[i].index;
        }
 
        for (int i = 0; i <= q; ++i) {
            mx = Math.max(mx, sortedAnsTemp[i].x);
        }
         
          // Mx will be mx + 2 as while calculating
        // mx, we excluded element
        // at index left and right
        mx = mx + 2;
        return mx;
    }
 
    public static void main(String[] args) {
        int n = 6;
        ArrayList<Integer> v = new ArrayList<>(Arrays.asList(4, 2, 6, 5, 3, 1));
        System.out.println(maxLength(n, v));
    }
}


Python3




# Python implementation of the above approach
from typing import List
class Query:
    def __init__(self) -> None:
        self.l = 0
        self.r = 0
        self.x = 0
        self.index = 0
 
class Arrays:
    def __init__(self) -> None:
        self.val = 0
        self.index = 0
 
# Function to update the value in Fenwick tree
def update(Fenwick: List[int], index: int, val: int, n: int) -> None:
    while (index <= n):
        Fenwick[index] += val
        index += index & (-index)
 
# Function to return the query result
def query(Fenwick: List[int], index: int, n: int) -> int:
    summ = 0
    while (index > 0):
        summ = summ + Fenwick[index]
        index -= index & (-index)
    return summ
 
# Function to return the length of subsequence
def maxLength(n: int, v: List[int]) -> int:
    where = [0 for _ in range(n + 2)]
    arr = [Arrays() for _ in range(n)]
 
    # Store the value in struct Array
    for i in range(1, n + 1):
        v[i - 1] = v[i - 1] - 1
        x = v[i - 1]
        where[x] = i - 1
        arr[i - 1].val = x
        arr[i - 1].index = i - 1
 
    # If less than 2 elements are
    # present return that element.
    if (n <= 2):
        print(n)
        return 0
 
    # Set the left and right pointers to extreme
    left = n
    right = 0
    mx = 0
    queries = [Query() for _ in range(4 * n)]
    j = 0
    for i in range(n - 1, -1, -1):
 
        # Calculate left and right pointer index.
        left = min(left, where[i])
        right = max(right, where[i])
        diff = right - left
        if (diff == 0 or diff == 1):
            continue
        val1 = v[left]
        val2 = v[right]
        minn = min(val1, val2)
 
        # Store the queries from [L+1, R-1].
        queries[j].l = left + 1
        queries[j].r = right - 1
        queries[j].x = minn
        queries[j].index = j
        j += 1
    Fenwick = [0 for _ in range(n + 1)]
    q = j - 1
 
    # Sort array and queries for fenwick updates
    arr[:n + 1].sort(key=lambda x: x.val)
    queries[:q + 1].sort(key=lambda val: val.x)
    curr = 0
    ans = [0 for _ in range(q + 1)]
 
    # For each query calculate maxx for
    # the answer and store it in ans array.
    for i in range(q + 1):
        while (arr[curr].val <= queries[i].x and curr < n):
            update(Fenwick, arr[curr].index + 1, 1, n)
            curr += 1
 
        # if queries[i].index < q:
        ans[queries[i].index] = query(Fenwick, queries[i].r + 1, n) - query(
            Fenwick, queries[i].l, n)
    for i in range(q + 1):
        mx = max(mx, ans[i])
 
    # Mx will be mx + 2 as while calculating
    # mx, we excluded element
    # at index left and right
    mx = mx + 2
    return mx
 
# Driver Code
if __name__ == "__main__":
 
    n = 6
    v = [4, 2, 6, 5, 3, 1]
 
    print(maxLength(n, v))
 
# This code is contributed by sanjeev2552


C#




using System;
using System.Collections.Generic;
using System.Linq;
 
class Query
{
    public int l, r, x, index;
}
 
class Arrays
{
    public int val, index;
}
 
class ArraysComparer : IComparer<Arrays>
{
    public int Compare(Arrays x, Arrays y)
    {
        return x.val.CompareTo(y.val);
    }
}
 
class QueryComparer : IComparer<Query>
{
    public int Compare(Query x, Query y)
    {
        return x.x.CompareTo(y.x);
    }
}
 
class Program
{
    // Function to update Fenwick tree with a value at a specific index
    static void Update(int[] Fenwick, int index, int val, int n)
    {
        while (index <= n)
        {
            Fenwick[index] += val;
            index += index & (-index);
        }
    }
 
    // Function to perform a query on Fenwick tree up to a specific index
    static int Query(int[] Fenwick, int index)
    {
        int sum = 0;
        while (index > 0)
        {
            sum += Fenwick[index];
            index -= index & (-index);
        }
        return sum;
    }
 
    // Function to find the maximum length of a subsequence with specific conditions
    static int MaxLength(int n, List<int> v)
    {
        // Array to store positions of elements in the input list 'v'
        int[] where = new int[n + 2];
        Array.Fill(where, 0);
 
        // Array of 'Arrays' objects to store values and their indices
        Arrays[] arr = new Arrays[n];
 
        // Preprocessing: store values and their positions in 'arr' and 'where' arrays
        for (int i = 1; i <= n; ++i)
        {
            v[i - 1] = v[i - 1] - 1;
            int x = v[i - 1];
            where[x] = i - 1;
            arr[i - 1] = new Arrays { val = x, index = i - 1 };
        }
 
        // If the input size is small (<= 2), return the size as the maximum length
        if (n <= 2)
        {
            Console.WriteLine(n);
            return 0;
        }
 
        // Initialize variables for tracking indices and maximum length
        int left = n, right = 0, mx = 0;
        Query[] queries = new Query[4 * n];
        int j = 0;
 
        // Creating queries based on certain conditions
        for (int i = n - 1; i >= 0; --i)
        {
            left = Math.Min(left, where[i]);
            right = Math.Max(right, where[i]);
            int diff = right - left;
 
            if (diff == 0 || diff == 1)
            {
                continue; // Skip if the difference is 0 or 1
            }
 
            int val1 = v[left];
            int val2 = v[right];
            int minn = Math.Min(val1, val2);
 
            // Store the query details in 'queries' array
            queries[j] = new Query { l = left + 1, r = right - 1, x = minn, index = j };
            ++j;
        }
 
        // Initialize Fenwick tree and the count of queries
        int[] Fenwick = new int[n + 1];
        Array.Fill(Fenwick, 0);
        int q = j - 1;
 
        // Sort 'arr' array using custom comparer
        Array.Sort(arr, 0, n, new ArraysComparer());
        // Sort 'queries' array using custom comparer
        Array.Sort(queries, 0, q + 1, new QueryComparer());
 
        int curr = 0;
        int[] ans = new int[q + 1];
        Array.Fill(ans, 0);
 
        // Process queries to find maximum subsequence length
        for (int i = 0; i <= q; ++i)
        {
            while (curr < n && arr[curr].val <= queries[i].x)
            {
                Update(Fenwick, arr[curr].index + 1, 1, n);
                curr++;
            }
 
            ans[queries[i].index] = Query(Fenwick, queries[i].r + 1) - Query(Fenwick, queries[i].l);
        }
 
        // Find the maximum length
        for (int i = 0; i <= q; ++i)
        {
            mx = Math.Max(mx, ans[i]);
        }
 
        mx = mx + 2; // Add 2 to the maximum length
        return mx;
    }
 
    static void Main()
    {
        int n = 6;
        List<int> v = new List<int> { 4, 2, 6, 5, 3, 1 };
 
        Console.WriteLine(MaxLength(n, v));
    }
}


Javascript




<script>
    //JavaScript code for the above approach
    function Query() {
      this.l = 0;
      this.r = 0;
      this.x = 0;
      this.index = 0;
    }
 
    function Arrays() {
      this.val = 0;
      this.index = 0;
    }
 
    // Function to update the value in Fenwick tree
    function update(Fenwick, index, val, n) {
      while (index <= n) {
        Fenwick[index] += val;
        index += index & (-index);
      }
    }
 
    // Function to return the query result
    function query(Fenwick, index, n) {
      let summ = 0;
      while (index > 0) {
        summ += Fenwick[index];
        index -= index & (-index);
      }
      return summ;
    }
 
    // Function to return the length of subsequence
    function maxLength(n, v) {
      const where = Array(n + 2).fill(0);
      const arr = Array(n).fill(0).map(() => new Arrays());
 
      // Store the value in struct Array
      for (let i = 1; i <= n; i++) {
        v[i - 1] = v[i - 1] - 1;
        const x = v[i - 1];
        where[x] = i - 1;
        arr[i - 1].val = x;
        arr[i - 1].index = i - 1;
      }
 
      // If less than 2 elements are
      // present return that element.
      if (n <= 2) {
        console.log(n);
        return 0;
      }
 
      // Set the left and right pointers to extreme
      let left = n;
      let right = 0;
      let mx = 0;
      const queries = Array(4 * n).fill(0).map(() => new Query());
      let j = 0;
      for (let i = n - 1; i >= 0; i--) {
        // Calculate left and right pointer index.
        left = Math.min(left, where[i]);
        right = Math.max(right, where[i]);
        const diff = right - left;
        if (diff === 0 || diff === 1) {
          continue;
        }
        const val1 = v[left];
        const val2 = v[right];
        const minn = Math.min(val1, val2);
 
        // Store the queries from [L+1, R-1].
        queries[j].l = left + 1;
        queries[j].r = right - 1;
        queries[j].x = minn;
        queries[j].index = j;
        j++;
      }
      const Fenwick = Array(n + 1).fill(0);
      const q = j - 1;
 
      // Sort array and queries for fenwick updates
      arr.slice(0, n + 1).sort((a, b) => a.val - b.val);
      queries.slice(0, q + 1).sort((a, b) => a.x - b.x);
      let curr = 0;
      const ans = Array(q + 1).fill(0);
 
 
      // For each query calculate maxx for
      // the answer and store it in ans array.
      for (let i = 0; i <= q; i++) {
        while (arr[curr].val <= queries[i].x && curr < n) {
          update(Fenwick, arr[curr].index + 1, 1, n);
          curr++;
        }
 
        ans[queries[i].index] = query(Fenwick, queries[i].r + 1, n) - query(Fenwick, queries[i].l, n);
      }
      for (let i = 0; i <= q; i++) {
        mx = Math.max(mx, ans[i]);
      }
 
      // Mx will be mx + 2 as while calculating
      // mx, we excluded element
      // at index left and right
      mx = mx + 2;
      return mx;
    }
 
    // Driver Code
 
    const n = 6;
    const v = [4, 2, 6, 5, 3, 1];
 
    document.write(maxLength(n, v));
 
 
 // This code is contributed by Potta Lokesh
 
  </script>


Output

3

Time Complexity: O(nlogn), where N is number of elements in the given range of the vector.
Auxiliary Space: O(n)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads