Open In App

Find Maximum Number of Removal Queries That Can Be Processed I

Given an array called arr[] and another array queries[]. You can perform an operation on arr at most once, replacing it with a subsequence of itself. Then, you process the queries in order. If the first and last elements of arr are both less than a query value queries[i], the processing ends. Otherwise, you can remove either the first or the last element of arr if it is greater than or equal to the query value. The task is to find the maximum number of queries that can be processed optimally.

Example:

Input: arr = {1,2,3,4,5}, queries = {1,2,3,4,6}
Output: 4
Explanation: The process for the queries is as follows:

  • We choose and remove arr[0] since 1 <= 1, then arr becomes [2,3,4,5].
  • We choose and remove arr[0] since 2 <= 2, then arr becomes [3,4,5].
  • We choose and remove arr[0] since 3 <= 3, then arr becomes [4,5].
  • We choose and remove arr[0] since 4 <= 4, then arr becomes [5].
  • We cannot choose any elements from arr since they are not greater than or equal to 5. Hence, the answer is 4. It can be shown that we can't process more than 4 queries.

Input: arr = {2,3,2}, queries = {2,2,3}
Output: 3
Explanation: The process for the queries is as follows:

  • We choose and remove arr[0] since 2 <= 2, then arr becomes {3,2}.
  • We choose and remove arr[1] since 2 <= 2, then arr becomes {3}.
  • We choose and remove arr[0] since 3 <= 3, then arr becomes []. Hence, the answer is 3. It can be shown that we can't process more than 3 queries.

Approach:

First, if we can do x operations, we can definitely do x−1 operations as well, which means we can use binary search to find the maximum operations.

Second, think of this problem: Given two arrays A and B with the same size. Initially, we have an empty array C, and we iterate each element in B. For each element, we can either put it in the leftmost of C, or put it in the rightmost of C. After all the operations, can we make A equal to C?

Solution: We can use DP to solve this problem. Let's say if dp[l][r] is true, then [l,r] in A can be obtained by the prefix of B with length r-l+1. For transition, dp[l][r] can be determined by dp[l+1][r] or dp[l][r-1]:

  • if dp[l+1][r] is true, and B[r-l]==A[l],
  • or dp[l][r-1] is true, and B[r-l]==A[r],

Can we convert the original problem to this one?

Actually, yes! But we need to reverse the queries, and choose a suffix as array B.

Also, we define dp[l][r] as the longest subsequence that can be obtained by [l,r] in arr, because in the original problem, we should choose a subsequence first. Then, as for transition, dp[l][r] can be determined by dp[l+1][r] or dp[l][r-1]: dp[l][r]=max(dp[l+1][r]+(a[l]>=queries[dp[l+1][r]]), dp[l][r-1]+(a[r]>=queries[dp[l][r-1]])).

If any dp[l][r] equals to the length of the suffix, we can get a subsquence of arr from the suffix.

Finally, we can use binary search to find the length of suffix of B, and the longest length is the answer.

Step-by-step approach:

Below is the implementation of the above approach:

#include <bits/stdc++.h>
using namespace std;

// This function returns the maximum number of queries that
// can be processed given an array 'arr' and a vector of
// queries 'queries'.
int maximumProcessableQueries(vector<int>& arr,
                              vector<int>& queries)
{
    // Reverse the queries vector to process them in reverse
    // order.
    reverse(queries.begin(), queries.end());

    // Get the size of the array 'arr' and the number of
    // queries.
    int n = (int)arr.size();
    int m = (int)queries.size();

    // Define a lambda function 'Check' that takes an
    // integer 'length' as an argument and returns a boolean
    // indicating whether it is possible to process 'length'
    // queries using the array 'arr'.
    auto Check = [&](int length) -> bool {
        // Calculate the index 'd' in the reversed queries
        // vector corresponding to the start of the queries
        // to be processed.
        int d = m - length;

        // Create a 2D vector 'dp' to store the maximum
        // number of queries that can be processed for each
        // subarray of 'arr'.
        vector<vector<int> > dp(n, vector<int>(n));

        // Iterate over the length of the subarrays.
        for (int len = 1; len <= n; len++) {
            // Iterate over the starting indices of the
            // subarrays.
            for (int l = 0; l + len - 1 < n; l++) {
                // Calculate the ending index of the
                // subarray.
                int r = l + len - 1;

                // If the subarray has length 1, then the
                // maximum number of queries that can be
                // processed is 1 if the element in 'arr' is
                // greater than or equal to the query at
                // index 'd'.
                if (len == 1) {
                    dp[l][r]
                        = (int)(arr[r] >= queries[d + 0]);
                    continue;
                }

                // Calculate the maximum number of queries
                // that can be processed by extending the
                // subarray to the left or right.
                int x = 0;
                if (d + dp[l][r - 1] < m) {
                    x = (int)(arr[r]
                              >= queries[d + dp[l][r - 1]]);
                }
                int y = 0;
                if (d + dp[l + 1][r] < m) {
                    y = (int)(arr[l]
                              >= queries[d + dp[l + 1][r]]);
                }

                // Update the maximum number of queries that
                // can be processed for the current
                // subarray.
                dp[l][r] = max(dp[l][r - 1] + x,
                               dp[l + 1][r] + y);

                // If the maximum number of queries that can
                // be processed for the current subarray is
                // equal to 'length', then return true.
                if (dp[l][r] == length) {
                    return true;
                }
            }
        }

        // If no subarray can process 'length' queries,
        // return false.
        return false;
    };

    // Perform binary search to find the maximum number of
    // queries that can be processed.
    int l = 0, r = m;
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        if (Check(mid)) {
            l = mid;
        }
        else {
            r = mid - 1;
        }
    }

    // Return the maximum number of queries that can be
    // processed.
    return r;
}

int main()
{
    // Define the input array 'arr'.
    vector<int> arr = { 1, 2, 3, 4, 5 };

    // Define the vector of queries.
    vector<int> queries = { 1, 2, 3, 4, 6 };

    // Find the maximum number of queries that can be
    // processed.
    int result = maximumProcessableQueries(arr, queries);

    // Print the result.
    cout << result << endl;

    return 0;
}
import java.util.*;

public class Main {

    // This function returns the maximum number of queries that
    // can be processed given an array 'arr' and a vector of
    // queries 'queries'.
    static int maximumProcessableQueries(List<Integer> arr, List<Integer> queries) {
        // Reverse the queries list to process them in reverse
        // order.
        Collections.reverse(queries);

        // Get the size of the array 'arr' and the number of
        // queries.
        int n = arr.size();
        int m = queries.size();

        // Define a lambda function 'Check' that takes an
        // integer 'length' as an argument and returns a boolean
        // indicating whether it is possible to process 'length'
        // queries using the array 'arr'.
        // Here, we're using a nested class instead of lambda for simplicity.
        class Checker {
            boolean Check(int length) {
                // Calculate the index 'd' in the reversed queries
                // list corresponding to the start of the queries
                // to be processed.
                int d = m - length;

                // Create a 2D array 'dp' to store the maximum
                // number of queries that can be processed for each
                // subarray of 'arr'.
                int[][] dp = new int[n][n];

                // Iterate over the length of the subarrays.
                for (int len = 1; len <= n; len++) {
                    // Iterate over the starting indices of the
                    // subarrays.
                    for (int l = 0; l + len - 1 < n; l++) {
                        // Calculate the ending index of the
                        // subarray.
                        int r = l + len - 1;

                        // If the subarray has length 1, then the
                        // maximum number of queries that can be
                        // processed is 1 if the element in 'arr' is
                        // greater than or equal to the query at
                        // index 'd'.
                        if (len == 1) {
                            dp[l][r] = arr.get(r) >= queries.get(d + 0) ? 1 : 0;
                            continue;
                        }

                        // Calculate the maximum number of queries
                        // that can be processed by extending the
                        // subarray to the left or right.
                        int x = 0;
                        if (d + dp[l][r - 1] < m) {
                            x = arr.get(r) >= queries.get(d + dp[l][r - 1]) ? 1 : 0;
                        }
                        int y = 0;
                        if (d + dp[l + 1][r] < m) {
                            y = arr.get(l) >= queries.get(d + dp[l + 1][r]) ? 1 : 0;
                        }

                        // Update the maximum number of queries that
                        // can be processed for the current
                        // subarray.
                        dp[l][r] = Math.max(dp[l][r - 1] + x, dp[l + 1][r] + y);

                        // If the maximum number of queries that can
                        // be processed for the current subarray is
                        // equal to 'length', then return true.
                        if (dp[l][r] == length) {
                            return true;
                        }
                    }
                }

                // If no subarray can process 'length' queries,
                // return false.
                return false;
            }
        }

        Checker checker = new Checker();

        // Perform binary search to find the maximum number of
        // queries that can be processed.
        int l = 0, r = m;
        while (l < r) {
            int mid = (l + r + 1) >> 1;
            if (checker.Check(mid)) {
                l = mid;
            } else {
                r = mid - 1;
            }
        }

        // Return the maximum number of queries that can be
        // processed.
        return r;
    }

    public static void main(String[] args) {
        // Define the input array 'arr'.
        List<Integer> arr = Arrays.asList(1, 2, 3, 4, 5);
        // Define the list of queries.
        List<Integer> queries = Arrays.asList(1, 2, 3, 4, 6);

        // Find the maximum number of queries that can be
        // processed.
        int result = maximumProcessableQueries(arr, queries);

        // Print the result.
        System.out.println(result);
    }
}
//this code is contributed by Utkarsh
from typing import List

# Define a function that returns the maximum number of queries
# that can be processed given an array 'arr' and a list of
# queries 'queries'.
def maximum_processable_queries(arr: List[int], queries: List[int]) -> int:
    # Reverse the queries list to process them in reverse order.
    queries.reverse()

    # Get the size of the array 'arr' and the number of queries.
    n = len(arr)
    m = len(queries)

    # Define a nested function 'check' that takes an integer
    # 'length' as an argument and returns a boolean indicating
    # whether it is possible to process 'length' queries using
    # the array 'arr'.
    def check(length: int) -> bool:
        # Calculate the index 'd' in the reversed queries list
        # corresponding to the start of the queries to be
        # processed.
        d = m - length

        # Create a 2D list 'dp' to store the maximum number of
        # queries that can be processed for each subarray of 'arr'.
        dp = [[0] * n for _ in range(n)]

        # Iterate over the length of the subarrays.
        for length in range(1, n + 1):
            # Iterate over the starting indices of the subarrays.
            for l in range(n - length + 1):
                # Calculate the ending index of the subarray.
                r = l + length - 1

                # If the subarray has length 1, then the maximum
                # number of queries that can be processed is 1 if
                # the element in 'arr' is greater than or equal to
                # the query at index 'd'.
                if length == 1:
                    dp[l][r] = 1 if arr[r] >= queries[d] else 0
                    continue

                # Calculate the maximum number of queries that can
                # be processed by extending the subarray to the
                # left or right.
                x = 1 if d + dp[l][r - 1] < m and arr[r] >= queries[d + dp[l][r - 1]] else 0
                y = 1 if d + dp[l + 1][r] < m and arr[l] >= queries[d + dp[l + 1][r]] else 0

                # Update the maximum number of queries that can be
                # processed for the current subarray.
                dp[l][r] = max(dp[l][r - 1] + x, dp[l + 1][r] + y)

                # If the maximum number of queries that can be
                # processed for the current subarray is equal to
                # 'length', then return True.
                if dp[l][r] == length:
                    return True

        # If no subarray can process 'length' queries, return False.
        return False

    # Perform binary search to find the maximum number of
    # queries that can be processed.
    l, r = 0, m
    while l < r:
        mid = (l + r + 1) >> 1
        if check(mid):
            l = mid
        else:
            r = mid - 1

    # Return the maximum number of queries that can be processed.
    return r

# Define the input array 'arr'.
arr = [1, 2, 3, 4, 5]
# Define the list of queries.
queries = [1, 2, 3, 4, 6]

# Find the maximum number of queries that can be processed.
result = maximum_processable_queries(arr, queries)

# Print the result.
print(result)
#this code is contributed by Prachi.
// This function returns the maximum number of queries that
// can be processed given an array 'arr' and a vector of
// queries 'queries'.
function maximumProcessableQueries(arr, queries) {
    // Reverse the queries array to process them in reverse order.
    queries.reverse();

    // Get the length of the array 'arr' and the number of queries.
    const n = arr.length;
    const m = queries.length;

    // Define a function 'check' that takes an integer 'length'
    // as an argument and returns a boolean indicating whether
    // it is possible to process 'length' queries using the array 'arr'.
    function check(length) {
        // Calculate the index 'd' in the reversed queries array
        // corresponding to the start of the queries to be processed.
        const d = m - length;

        // Create a 2D array 'dp' to store the maximum number
        // of queries that can be processed for each subarray of 'arr'.
        const dp = Array.from({ length: n }, () => Array(n).fill(0));

        // Iterate over the length of the subarrays.
        for (let len = 1; len <= n; len++) {
            // Iterate over the starting indices of the subarrays.
            for (let l = 0; l + len - 1 < n; l++) {
                // Calculate the ending index of the subarray.
                const r = l + len - 1;

                // If the subarray has length 1, then the maximum
                // number of queries that can be processed is 1
                // if the element in 'arr' is greater than or equal
                // to the query at index 'd'.
                if (len === 1) {
                    dp[l][r] = arr[r] >= queries[d + 0] ? 1 : 0;
                    continue;
                }

                // Calculate the maximum number of queries that
                // can be processed by extending the subarray
                // to the left or right.
                let x = 0;
                if (d + dp[l][r - 1] < m) {
                    x = arr[r] >= queries[d + dp[l][r - 1]] ? 1 : 0;
                }
                let y = 0;
                if (d + dp[l + 1][r] < m) {
                    y = arr[l] >= queries[d + dp[l + 1][r]] ? 1 : 0;
                }

                // Update the maximum number of queries that can
                // be processed for the current subarray.
                dp[l][r] = Math.max(dp[l][r - 1] + x, dp[l + 1][r] + y);

                // If the maximum number of queries that can be
                // processed for the current subarray is equal
                // to 'length', then return true.
                if (dp[l][r] === length) {
                    return true;
                }
            }
        }

        // If no subarray can process 'length' queries, return false.
        return false;
    }

    // Perform binary search to find the maximum number of
    // queries that can be processed.
    let l = 0,
        r = m;
    while (l < r) {
        const mid = ((l + r + 1) >> 1);
        if (check(mid)) {
            l = mid;
        } else {
            r = mid - 1;
        }
    }

    // Return the maximum number of queries that can be processed.
    return r;
}

// Define the input array 'arr'.
const arr = [1, 2, 3, 4, 5];
// Define the list of queries.
const queries = [1, 2, 3, 4, 6];

// Find the maximum number of queries that can be processed.
const result = maximumProcessableQueries(arr, queries);

// Print the result.
console.log(result);

Output
4

Time complexity: O(n2log(n))
Auxiliary Space: O(n2log(n))

Article Tags :