Query to check if a range is made up of consecutive elements

Given an array of n non-consecutive integers and Q queries, the task is to check whether for the given range l and r, the elements are consecutive or not.

Examples:

Input: arr = { 2, 4, 3, 7, 6, 1}, Q = { (1, 3), (3, 5), (5, 6) }
Output: Yes, No, No
Explanation: Array elements from (1, 3) = {2, 4, 3}, (3, 5) = {3, 7, 6}, (5, 6) = {6, 1}
So the answer is Yes, No, No



Input: arr = {1, 2, 3, 4, 5}, Q = { (1, 2), (4, 5), (1, 5) }
Output:Yes, Yes, Yes

Naive Approach:
The sub array between range l and r can be sorted and checked if it contains consequetive elements or not.

Time Complexity: O(q*n*log n)
where n is the size of the array and q is the number of queries.

Efficient approach:

  1. A segment tree can be used to get the minimum and maximum in a range.
  2. If the minimum element of a sub array is x and the maximum element is y then we can there is no element less than x and more than y, so we can say that x<=arr[i]<=y.
  3. As there are no repeated elements, so it can be concluded that if the difference of maximum and minimum element + 1 is equal to the length of the range (r-l+1) then the range consists of consecutive elements.

Below is the implementation of the above approach.

CPP

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the above approach.
#include <bits/stdc++.h>
using namespace std;
  
// Segment tree
int tree_min[1000001],
    tree_max[1000001];
  
// Functions to return
// minimum and maximum
int min(int a, int b)
{
    return a < b ? a : b;
}
  
int max(int a, int b)
{
    return a > b ? a : b;
}
  
// Segment tree for minimum element
void build_min(int array[], int node,
               int left, int right)
{
    // If left is equal to right
    if (left == right)
        tree_min[node] = array[left];
  
    else {
        // Divide the segment into equal halves
        build_min(array, 2 * node, left,
                  (left + right) / 2);
  
        build_min(array, 2 * node + 1,
                  (left + right) / 2 + 1, right);
  
        // Update the element as minimum
        // of the divided two subarrays
        tree_min[node] = min(tree_min[2 * node],
                             tree_min[2 * node + 1]);
    }
}
  
// Query to find a minimum
// in a given ranges
int query_min(int node, int c_l,
              int c_r, int l, int r)
{
    // Out of range
    if (c_l > r || c_r < l)
        return 1e9;
  
    // Within the range completely
    if (c_l >= l && c_r <= r)
        return tree_min[node];
    else
        // Divide the range into two halves
        // Query for each half
        // and return the minimum of two
        return min(query_min(2 * node, c_l,
                             (c_l + c_r) / 2, l, r),
                   query_min(2 * node + 1,
                             (c_l + c_r) / 2 + 1,
                             c_r, l, r));
}
  
// Segment tree for maximum element
void build_max(int array[], int node,
               int left, int right)
{
    // If left is equal to right
    if (left == right)
        tree_max[node] = array[left];
  
    else {
        // Divide the segment into equal halves
        build_max(array, 2 * node, left,
                  (left + right) / 2);
  
        build_max(array, 2 * node + 1,
                  (left + right) / 2 + 1, right);
  
        // Update the element as maximum
        // of the divided two subarrays
        tree_max[node] = max(tree_max[2 * node],
                             tree_max[2 * node + 1]);
    }
}
  
// Query to find maximum
// in a given ranges
int query_max(int node, int c_l,
              int c_r, int l, int r)
{
    // Out of range
    if (c_l > r || c_r < l)
        return -1;
  
    // Within the range completely
    if (c_l >= l && c_r <= r)
        return tree_max[node];
    else
        // Divide the range into two halves
        // and query for each half
        // and return the maximum of two
        return max(query_max(2 * node, c_l,
                             (c_l + c_r) / 2, l, r),
                   query_max(2 * node + 1,
                             (c_l + c_r) / 2 + 1,
                             c_r, l, r));
}
  
// Build the tree
void init(int array[], int n)
{
    build_min(array, 1, 0, n - 1);
    build_max(array, 1, 0, n - 1);
}
  
// Check if the given range is Consecutive
bool isConsecutive(int x, int y, int n)
{
    return ((query_max(1, 0, n - 1, x, y)
             - query_min(1, 0, n - 1, x, y))
            == (y - x));
}
  
// Driver code
int main()
{
    int arr[] = { 2, 4, 3, 7, 6, 1 };
    int query[][2] = { { 1, 3 }, { 3, 5 }, { 5, 6 } };
    int n = sizeof(arr) / sizeof(int), q = 3;
    init(arr, n);
  
    for (int i = 0; i < q; i++) {
        int l, r;
        l = query[i][0];
        r = query[i][1];
  
        cout << (isConsecutive(l - 1, r - 1, n) ? 
                           "Yes" : "No") << "\n";
    }
  
    return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of the above approach.
class GFG
{
  
    // Segment tree
    static int[] tree_min = new int[1000001];
    static int[] tree_max = new int[1000001];
  
    // Functions to return
    // minimum and maximum
    static int min(int a, int b) 
    {
        return a < b ? a : b;
    }
  
    static int max(int a, int b) 
    {
        return a > b ? a : b;
    }
  
    // Segment tree for minimum element
    static void build_min(int array[], int node, int left, int right)
    {
        // If left is equal to right
        if (left == right)
            tree_min[node] = array[left];
  
        else
        {
            // Divide the segment into equal halves
            build_min(array, 2 * node, left, (left + right) / 2);
  
            build_min(array, 2 * node + 1,
                    (left + right) / 2 + 1, right);
  
            // Update the element as minimum
            // of the divided two subarrays
            tree_min[node] = Math.min(tree_min[2 * node],
                    tree_min[2 * node + 1]);
        }
    }
  
    // Query to find a minimum
    // in a given ranges
    static int query_min(int node, int c_l, int c_r, int l, int r) 
    {
        // Out of range
        if (c_l > r || c_r < l)
            return (int) 1e9;
  
        // Within the range completely
        if (c_l >= l && c_r <= r)
            return tree_min[node];
        else
            // Divide the range into two halves
            // Query for each half
            // and return the minimum of two
            return min(query_min(2 * node, c_l, (c_l + c_r) / 2, l, r),
                    query_min(2 * node + 1, (c_l + c_r) / 2 + 1, c_r, l, r));
    }
  
    // Segment tree for maximum element
    static void build_max(int array[], int node, int left, int right) 
    {
        // If left is equal to right
        if (left == right)
            tree_max[node] = array[left];
  
        else 
        {
            // Divide the segment into equal halves
            build_max(array, 2 * node, left, (left + right) / 2);
  
            build_max(array, 2 * node + 1, (left + right) / 2 + 1, right);
  
            // Update the element as maximum
            // of the divided two subarrays
            tree_max[node] = Math.max(tree_max[2 * node],
                    tree_max[2 * node + 1]);
        }
    }
  
    // Query to find maximum
    // in a given ranges
    static int query_max(int node, int c_l, int c_r, int l, int r)
    {
        // Out of range
        if (c_l > r || c_r < l)
            return -1;
  
        // Within the range completely
        if (c_l >= l && c_r <= r)
            return tree_max[node];
        else
            // Divide the range into two halves
            // and query for each half
            // and return the maximum of two
            return Math.max(query_max(2 * node, c_l, (c_l + c_r) / 2, l, r),
                    query_max(2 * node + 1, (c_l + c_r) / 2 + 1, c_r, l, r));
    }
  
    // Build the tree
    static void init(int array[], int n)
    {
        build_min(array, 1, 0, n - 1);
        build_max(array, 1, 0, n - 1);
    }
  
    // Check if the given range is Consecutive
    static boolean isConsecutive(int x, int y, int n)
    {
        return ((query_max(1, 0, n - 1, x, y) -
                query_min(1, 0, n - 1, x, y)) == (y - x));
    }
  
    // Driver code
    public static void main(String[] args)
    {
        int arr[] = { 2, 4, 3, 7, 6, 1 };
        int query[][] = { { 1, 3 }, { 3, 5 }, { 5, 6 } };
        int n = arr.length, q = 3;
        init(arr, n);
  
        for (int i = 0; i < q; i++)
        {
            int l, r;
            l = query[i][0];
            r = query[i][1];
  
            System.out.print((isConsecutive(l - 1, r - 1, n) ? 
                    "Yes" : "No") + "\n");
        }
    }
}
  
// This code is contributed by PrinciRaj1992

chevron_right


Python

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 implementation of the above approach.
  
# Segment tree
tree_min = [0] * 1000001
  
tree_max = [0] * 1000001
  
# Segment tree for minimum element
def build_min(array, node,left, right):
  
    # If left is equal to right
    if (left == right):
        tree_min[node] = array[left]
  
    else :
        # Divide the segment into equal halves
        build_min(array, 2 * node, left,(left + right) // 2)
  
        build_min(array, 2 * node + 1,(left + right) // 2 + 1, right)
  
        # Update the element as minimum
        # of the divided two subarrays
        tree_min[node] = min(tree_min[2 * node], tree_min[2 * node + 1])
  
# Query to find a minimum
# in a given ranges
def query_min(node, c_l, c_r, l, r):
  
    # Out of range
    if (c_l > r or c_r < l):
        return 10**9
  
    # Within the range completely
    if (c_l >= l and c_r <= r):
        return tree_min[node]
    else:
        # Divide the range into two halves
        # Query for each half
        # and return the minimum of two
        return min(query_min(2 * node, c_l,(c_l + c_r) // 2, l, r),
                query_min(2 * node + 1, (c_l + c_r) // 2 + 1,c_r, l, r))
  
# Segment tree for maximum element
def build_max(array, node, left, right):
  
    # If left is equal to right
    if (left == right):
        tree_max[node] = array[left]
  
    else :
        # Divide the segment into equal halves
        build_max(array, 2 * node, left,(left + right) // 2)
  
        build_max(array, 2 * node + 1,(left + right) // 2 + 1, right)
  
        # Update the element as maximum
        # of the divided two subarrays
        tree_max[node] = max(tree_max[2 * node],tree_max[2 * node + 1])
  
# Query to find maximum
# in a given ranges
def query_max(node, c_l, c_r, l, r):
  
    # Out of range
    if (c_l > r or c_r < l):
        return -1
  
    # Within the range completely
    if (c_l >= l and c_r <= r):
        return tree_max[node]
    else:
        # Divide the range into two halves
        # and query for each half
        # and return the maximum of two
        return max(query_max(2 * node, c_l,(c_l + c_r) // 2, l, r),query_max(2 * node + 1,(c_l + c_r) // 2 + 1,c_r, l, r))
  
# Build the tree
def init(array, n):
  
    build_min(array, 1, 0, n - 1)
    build_max(array, 1, 0, n - 1)
  
# Check if the given range is Consecutive
def isConsecutive(x, y, n):
  
    return ((query_max(1, 0, n - 1, x, y) - query_min(1, 0, n - 1, x, y)) == (y - x))
  
# Driver code
  
arr = [2, 4, 3, 7, 6, 1]
query = [ [1, 3] , [3, 5 ], [5, 6] ]
n = len(arr)
q = 3
init(arr, n)
  
for i in range(q):
    l = query[i][0]
    r = query[i][1]
  
    if (isConsecutive(l - 1, r - 1, n) ):
        print("Yes")
    else:
        print("No")
  
# This code is contributed by mohit kumar 29

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# implementation of the above approach.
using System;
  
class GFG
{
  
    // Segment tree
    static int[] tree_min = new int[1000001];
    static int[] tree_max = new int[1000001];
  
    // Functions to return
    // minimum and maximum
    static int min(int a, int b) 
    {
        return a < b ? a : b;
    }
  
    static int max(int a, int b) 
    {
        return a > b ? a : b;
    }
  
    // Segment tree for minimum element
    static void build_min(int []array, int node,
                           int left, int right)
    {
        // If left is equal to right
        if (left == right)
            tree_min[node] = array[left];
  
        else
        {
            // Divide the segment into equal halves
            build_min(array, 2 * node, left, (left + right) / 2);
  
            build_min(array, 2 * node + 1,
                    (left + right) / 2 + 1, right);
  
            // Update the element as minimum
            // of the divided two subarrays
            tree_min[node] = Math.Min(tree_min[2 * node],
                    tree_min[2 * node + 1]);
        }
    }
  
    // Query to find a minimum
    // in a given ranges
    static int query_min(int node, int c_l, 
                        int c_r, int l, int r) 
    {
        // Out of range
        if (c_l > r || c_r < l)
            return (int) 1e9;
  
        // Within the range completely
        if (c_l >= l && c_r <= r)
            return tree_min[node];
        else
            // Divide the range into two halves
            // Query for each half
            // and return the minimum of two
            return min(query_min(2 * node, c_l, 
                        (c_l + c_r) / 2, l, r),
                        query_min(2 * node + 1, 
                        (c_l + c_r) / 2 + 1, c_r, l, r));
    }
  
    // Segment tree for maximum element
    static void build_max(int []array, int node, 
                           int left, int right) 
    {
        // If left is equal to right
        if (left == right)
            tree_max[node] = array[left];
  
        else
        {
            // Divide the segment into equal halves
            build_max(array, 2 * node, left, (left + right) / 2);
  
            build_max(array, 2 * node + 1, (left + right) / 2 + 1, right);
  
            // Update the element as maximum
            // of the divided two subarrays
            tree_max[node] = Math.Max(tree_max[2 * node],
                    tree_max[2 * node + 1]);
        }
    }
  
    // Query to find maximum
    // in a given ranges
    static int query_max(int node, int c_l, 
                        int c_r, int l, int r)
    {
        // Out of range
        if (c_l > r || c_r < l)
            return -1;
  
        // Within the range completely
        if (c_l >= l && c_r <= r)
            return tree_max[node];
        else
            // Divide the range into two halves
            // and query for each half
            // and return the maximum of two
            return Math.Max(query_max(2 * node, c_l,
                            (c_l + c_r) / 2, l, r),
                            query_max(2 * node + 1,
                            (c_l + c_r) / 2 + 1, c_r, l, r));
    }
  
    // Build the tree
    static void init(int []array, int n)
    {
        build_min(array, 1, 0, n - 1);
        build_max(array, 1, 0, n - 1);
    }
  
    // Check if the given range is Consecutive
    static bool isConsecutive(int x, int y, int n)
    {
        return ((query_max(1, 0, n - 1, x, y) -
                query_min(1, 0, n - 1, x, y)) == (y - x));
    }
  
    // Driver code
    public static void Main(String[] args)
    {
        int []arr = {2, 4, 3, 7, 6, 1};
        int [,]query = {{ 1, 3 }, { 3, 5 }, { 5, 6 }};
        int n = arr.Length, q = 3;
        init(arr, n);
  
        for (int i = 0; i < q; i++)
        {
            int l, r;
            l = query[i,0];
            r = query[i,1];
  
            Console.Write((isConsecutive(l - 1, r - 1, n) ? 
                    "Yes" : "No") + "\n");
        }
    }
}
  
// This code is contributed by Rajput-Ji

chevron_right


Output:

Yes
No
No

Time Complexity: O(Q*log(n))



My Personal Notes arrow_drop_up

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.