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))

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




My Personal Notes arrow_drop_up

Third year Department of Information Technology Jadavpur University

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.