Range Minimum Query - GeeksforGeeks

Range Minimum Query

Last Updated : 27 Oct, 2026

Given an integer array arr[] and a 2D integer array queries[][] of size q × 2, process all the queries using 0-based indexing. Each query [l, r] asks for the minimum element present in the subarray arr[l...r].

Example:

Input: arr[] = [1, 2, 3, 4], queries[][] = [[0, 2], [2, 3]]
Output: [1, 3]
Explanation:
Query [0, 2]: The elements in arr[0...2] are [1, 2, 3]. The minimum element is 1.
Query [2, 3]: The elements in arr[2...3] are [3, 4]. The minimum element is 3.

Input: arr[] = [7, 2, 9, 4], queries[][] = [[1, 1], [0, 3]]
Output: [2, 2]
Explanation:
Query [1, 1]: The subarray arr[1...1] contains only one element, 2. The minimum element is 2.
Query [0, 3]: The elements in arr[0...3] are [7, 2, 9, 4]. The minimum element is 2

Try It Yourself
redirect icon

[Naive Approach] Simple Traversal - O(q × n) Time and O(1) Space

For each query [l, r],

  • Traverse all the elements from index l to r and keep track of the minimum.
  • After the traversal, add the minimum to result.

This approach is straightforward, but in the worst case, each query may require traversing the entire array, making it inefficient when the number of queries is large.

C++
#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>
using namespace std;

vector<int> rangeMinQuery(vector<int>& arr, vector<vector<int>>& queries) {
    vector<int> ans;

    for (auto& query : queries) {
        int l = query[0];
        int r = query[1];

        int minEle = INT_MAX;

        // Traverse the current query range
        for (int i = l; i <= r; i++) {
            minEle = min(minEle, arr[i]);
        }

        // Store the minimum element of the range
        ans.push_back(minEle);
    }

    return ans;
}

int main() {
    vector<int> arr = {1, 2, 3, 4};
    vector<vector<int>> queries = {{0, 2}, {2, 3}};

    vector<int> ans = rangeMinQuery(arr, queries);

    for (int x : ans) {
        cout << x << " ";
    }

    return 0;
}
Java
import java.util.ArrayList;

class GFG {
    static ArrayList<Integer> rangeMinQuery(int[] arr, int[][] queries) {
        ArrayList<Integer> ans = new ArrayList<>();

        for (int[] query : queries) {
            int l = query[0];
            int r = query[1];

            int minEle = Integer.MAX_VALUE;

            // Traverse the current query range
            for (int i = l; i <= r; i++) {
                minEle = Math.min(minEle, arr[i]);
            }

            // Store the minimum element of the range
            ans.add(minEle);
        }

        return ans;
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};
        int[][] queries = {{0, 2}, {2, 3}};

        ArrayList<Integer> ans = rangeMinQuery(arr, queries);

        for (int x : ans) {
            System.out.print(x + " ");
        }
    }
}
Python
def rangeMinQuery(arr, queries):
    ans = []

    for l, r in queries:
        minEle = float('inf')

        # Traverse the current query range
        for i in range(l, r + 1):
            minEle = min(minEle, arr[i])

        # Store the minimum element of the range
        ans.append(minEle)

    return ans


if __name__ == "__main__":
    arr = [1, 2, 3, 4]
    queries = [[0, 2], [2, 3]]

    ans = rangeMinQuery(arr, queries)

    print(*ans)
C#
using System;
using System.Collections.Generic;

class GFG {
    static List<int> rangeMinQuery(int[] arr, int[][] queries) {
        List<int> ans = new List<int>();

        foreach (int[] query in queries) {
            int l = query[0];
            int r = query[1];

            int minEle = int.MaxValue;

            // Traverse the current query range
            for (int i = l; i <= r; i++) {
                minEle = Math.Min(minEle, arr[i]);
            }

            // Store the minimum element of the range
            ans.Add(minEle);
        }

        return ans;
    }

    static void Main() {
        int[] arr = { 1, 2, 3, 4 };
        int[][] queries = {
            new int[] { 0, 2 },
            new int[] { 2, 3 }
        };

        List<int> ans = rangeMinQuery(arr, queries);

        foreach (int x in ans) {
            Console.Write(x + " ");
        }
    }
}
JavaScript
function rangeMinQuery(arr, queries) {
    let ans = [];

    for (let query of queries) {
        let l = query[0];
        let r = query[1];

        let minEle = Infinity;

        // Traverse the current query range
        for (let i = l; i <= r; i++) {
            minEle = Math.min(minEle, arr[i]);
        }

        // Store the minimum element of the range
        ans.push(minEle);
    }

    return ans;
}

const arr = [1, 2, 3, 4];
const queries = [[0, 2], [2, 3]];

const ans = rangeMinQuery(arr, queries);

console.log(ans.join(" "));

Output
1 3 

[Better Approach] Precomputation Using 2D Array - O(n²) Time and O(n²) Space

The key idea is to precompute the minimum element for every possible subarray and store it in a 2D array pre, where pre[i][j] stores the minimum of arr[i...j]. This allows each query to be answered directly in O(1) time.

Steps by Steps approach:

  • Create a 2D array pre of size n × n.
  • For each starting index i, initialize minEle = arr[i].
  • Extend the range from i to the right and update minEle with the minimum element.
  • Store minEle in pre[i][j] for every range [i, j].
  • For each query [l, r], return pre[l][r] as the minimum element.
C++
#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>
using namespace std;

vector<int> rangeMinQuery(vector<int>& arr, vector<vector<int>>& queries) {
    int n = arr.size();

    // pre[i][j] stores minimum of arr[i...j]
    vector<vector<int>> pre(n, vector<int>(n));

    for (int i = 0; i < n; i++) {
        int minEle = arr[i];

        for (int j = i; j < n; j++) {
            minEle = min(minEle, arr[j]);
            pre[i][j] = minEle;
        }
    }

    vector<int> ans;

    // Answer each query in O(1)
    for (auto& query : queries) {
        int l = query[0];
        int r = query[1];

        ans.push_back(pre[l][r]);
    }

    return ans;
}

int main() {
    vector<int> arr = {1, 2, 3, 4};
    vector<vector<int>> queries = {{0, 2}, {2, 3}};

    vector<int> ans = rangeMinQuery(arr, queries);

    for (int x : ans) {
        cout << x << " ";
    }

    return 0;
}
Java
import java.util.ArrayList;

class GFG {
    static ArrayList<Integer> rangeMinQuery(int[] arr, int[][] queries) {
        int n = arr.length;

        // pre[i][j] stores minimum of arr[i...j]
        int[][] pre = new int[n][n];

        for (int i = 0; i < n; i++) {
            int minEle = arr[i];

            for (int j = i; j < n; j++) {
                minEle = Math.min(minEle, arr[j]);
                pre[i][j] = minEle;
            }
        }

        ArrayList<Integer> ans = new ArrayList<>();

        // Answer each query in O(1)
        for (int[] query : queries) {
            int l = query[0];
            int r = query[1];

            ans.add(pre[l][r]);
        }

        return ans;
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};
        int[][] queries = {{0, 2}, {2, 3}};

        ArrayList<Integer> ans = rangeMinQuery(arr, queries);

        for (int x : ans) {
            System.out.print(x + " ");
        }
    }
}
Python
def rangeMinQuery(arr, queries):
    n = len(arr)

    # pre[i][j] stores minimum of arr[i...j]
    pre = [[0] * n for _ in range(n)]

    for i in range(n):
        minEle = arr[i]

        for j in range(i, n):
            minEle = min(minEle, arr[j])
            pre[i][j] = minEle

    ans = []

    # Answer each query in O(1)
    for l, r in queries:
        ans.append(pre[l][r])

    return ans


if __name__ == "__main__":
    arr = [1, 2, 3, 4]
    queries = [[0, 2], [2, 3]]

    ans = rangeMinQuery(arr, queries)

    print(*ans)
C#
using System;
using System.Collections.Generic;

class GFG {
    static List<int> rangeMinQuery(int[] arr, int[][] queries) {
        int n = arr.Length;

        // pre[i][j] stores minimum of arr[i...j]
        int[,] pre = new int[n, n];

        for (int i = 0; i < n; i++) {
            int minEle = arr[i];

            for (int j = i; j < n; j++) {
                minEle = Math.Min(minEle, arr[j]);
                pre[i, j] = minEle;
            }
        }

        List<int> ans = new List<int>();

        // Answer each query in O(1)
        foreach (int[] query in queries) {
            int l = query[0];
            int r = query[1];

            ans.Add(pre[l, r]);
        }

        return ans;
    }

    static void Main() {
        int[] arr = { 1, 2, 3, 4 };
        int[][] queries = {
            new int[] { 0, 2 },
            new int[] { 2, 3 }
        };

        List<int> ans = rangeMinQuery(arr, queries);

        foreach (int x in ans) {
            Console.Write(x + " ");
        }
    }
}
JavaScript
function rangeMinQuery(arr, queries) {
    const n = arr.length;

    // pre[i][j] stores minimum of arr[i...j]
    const pre = Array.from({ length: n }, () => Array(n).fill(0));

    for (let i = 0; i < n; i++) {
        let minEle = arr[i];

        for (let j = i; j < n; j++) {
            minEle = Math.min(minEle, arr[j]);
            pre[i][j] = minEle;
        }
    }

    const ans = [];

    // Answer each query in O(1)
    for (const query of queries) {
        const l = query[0];
        const r = query[1];

        ans.push(pre[l][r]);
    }

    return ans;
}
//Driver Code

const arr = [1, 2, 3, 4];
const queries = [[0, 2], [2, 3]];

const ans = rangeMinQuery(arr, queries);

console.log(ans.join(" "));


[Expected Approach] Segment Tree - O(n + q log n) Time and O(n) Space

A Segment Tree stores the minimum element for different ranges of the array.

  • Each leaf represents an array element
  • Each internal node stores the minimum of its two child nodes.
  • Segment Tree is used here because result for a range can be computed in O(1) time using its two parts.

This allows us to answer a range minimum query efficiently.

Steps by steps approach:

  • Recursively divide the array into two halves until each segment contains a single element.
  • For each segment, store the minimum value of that segment in the corresponding segment tree node.
  • For a query [l, r], recursively traverse the tree to find the minimum value in the required range.
  • If the current segment lies completely inside [l, r], return the value stored at that node.
  • If the current segment lies completely outside [l, r], return INT_MAX.
  • If the segment partially overlaps with [l, r], recursively query both children and return the minimum of their results.
  • Repeat the process for all queries.
RangeMinimumQuery

Illustration:

Consider the input array: arr = [2, 5, 1, 4, 9, 3]
The Segment Tree divides the array into smaller ranges, and each node stores the minimum element of its range.

Step 1: Build the root node

  • The complete array represents the range [0, 5].
  • Divide it into [0, 2] and [3, 5].
  • Minimum of [0, 2] = min(2, 5, 1) = 1.
  • Minimum of [3, 5] = min(4, 9, 3) = 3.
  • Therefore, the root node for [0, 5] stores min(1, 3) = 1.

Step 2: Build the left part [0, 2]

  • Divide [0, 2] into [0, 1] and [2, 2].
  • Minimum of [0, 1] = min(2, 5) = 2.
  • [2, 2] contains only 1, so its minimum is 1.
  • Therefore, node [0, 2] stores min(2, 1) = 1.

Step 3: Build the right part [3, 5]

  • Divide [3, 5] into [3, 4] and [5, 5].
  • Minimum of [3, 4] = min(4, 9) = 4.
  • [5, 5] contains only 3, so its minimum is 3.
  • Therefore, node [3, 5] stores min(4, 3) = 3.

Step 4: Answer a query [0, 2]

  • The node representing [0, 2] lies completely inside the query range.
  • Directly return the value stored in this node, which is 1.
  • Hence, the answer is 1.

Step 5: Answer a query [2, 5]

  • The range [2, 5] overlaps with both sides of the root.
  • From the left subtree, consider the portion containing index 2, whose minimum is 1.
  • From the right subtree [3, 5], the stored minimum is 3.
  • Take the minimum of both parts: min(1, 3) = 1.
  • Hence, the answer is 1.
C++
#include <bits/stdc++.h>
using namespace std;

vector<int> tree;

void build(vector<int>& arr, int node, int start, int end) {
    if (start == end) {
        tree[node] = arr[start];
        return;
    }

    int mid = start + (end - start) / 2;

    build(arr, 2 * node + 1, start, mid);
    build(arr, 2 * node + 2, mid + 1, end);

    tree[node] = min(tree[2 * node + 1], tree[2 * node + 2]);
}

int query(int node, int start, int end, int l, int r) {
    // No overlap
    if (r < start || end < l)
        return INT_MAX;

    // Complete overlap
    if (l <= start && end <= r)
        return tree[node];

    int mid = start + (end - start) / 2;

    int leftMin = query(2 * node + 1, start, mid, l, r);
    int rightMin = query(2 * node + 2, mid + 1, end, l, r);

    return min(leftMin, rightMin);
}

vector<int> rangeMinQuery(vector<int>& arr, vector<vector<int>>& queries) {
    int n = arr.size();

    tree.resize(4 * n);

    // Build the segment tree
    build(arr, 0, 0, n - 1);

    vector<int> ans;

    // Process each query
    for (auto& q : queries) {
        ans.push_back(query(0, 0, n - 1, q[0], q[1]));
    }

    return ans;
}

int main() {
    vector<int> arr = {1, 2, 3, 4};
    vector<vector<int>> queries = {{0, 2}, {2, 3}};

    vector<int> ans = rangeMinQuery(arr, queries);

    for (int x : ans) {
        cout << x << " ";
    }

    return 0;
}
C
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>

int *tree;

void build(int arr[], int node, int start, int end)
{
    if (start == end)
    {
        tree[node] = arr[start];
        return;
    }

    int mid = start + (end - start) / 2;

    build(arr, 2 * node + 1, start, mid);
    build(arr, 2 * node + 2, mid + 1, end);

    tree[node] = tree[2 * node + 1] < tree[2 * node + 2]
                     ? tree[2 * node + 1]
                     : tree[2 * node + 2];
}

int query(int node, int start, int end, int l, int r)
{
    // No overlap
    if (r < start || end < l)
        return INT_MAX;

    // Complete overlap
    if (l <= start && end <= r)
        return tree[node];

    int mid = start + (end - start) / 2;

    int leftMin = query(2 * node + 1, start, mid, l, r);
    int rightMin = query(2 * node + 2, mid + 1, end, l, r);

    return leftMin < rightMin ? leftMin : rightMin;
}

void rangeMinQuery(int arr[], int n, int queries[][2], int q, int ans[])
{
    tree = (int *)malloc(4 * n * sizeof(int));

    // Build the segment tree
    build(arr, 0, 0, n - 1);

    // Process each query
    for (int i = 0; i < q; i++)
    {
        int l = queries[i][0];
        int r = queries[i][1];

        ans[i] = query(0, 0, n - 1, l, r);
    }

    free(tree);
}

int main()
{
    int arr[] = {1, 2, 3, 4};
    int n = 4;

    int queries[][2] = {
        {0, 2},
        {2, 3}
    };

    int q = 2;
    int ans[2];

    rangeMinQuery(arr, n, queries, q, ans);



    for (int i = 0; i < q; i++)
    {
        printf("%d", ans[i]);

        if (i < q - 1)
            printf(", ");
    }


    return 0;
}
Java
import java.util.ArrayList;

class GFG {
    static int[] tree;

    static void build(int[] arr, int node, int start, int end) {
        if (start == end) {
            tree[node] = arr[start];
            return;
        }

        int mid = start + (end - start) / 2;

        build(arr, 2 * node + 1, start, mid);
        build(arr, 2 * node + 2, mid + 1, end);

        tree[node] = Math.min(tree[2 * node + 1], tree[2 * node + 2]);
    }

    static int query(int node, int start, int end, int l, int r) {
        // No overlap
        if (r < start || end < l)
            return Integer.MAX_VALUE;

        // Complete overlap
        if (l <= start && end <= r)
            return tree[node];

        int mid = start + (end - start) / 2;

        int leftMin = query(2 * node + 1, start, mid, l, r);
        int rightMin = query(2 * node + 2, mid + 1, end, l, r);

        return Math.min(leftMin, rightMin);
    }

    static ArrayList<Integer> rangeMinQuery(int[] arr, int[][] queries) {
        int n = arr.length;

        tree = new int[4 * n];

        // Build the segment tree
        build(arr, 0, 0, n - 1);

        ArrayList<Integer> ans = new ArrayList<>();

        // Process each query
        for (int[] q : queries) {
            ans.add(query(0, 0, n - 1, q[0], q[1]));
        }

        return ans;
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};
        int[][] queries = {{0, 2}, {2, 3}};

        ArrayList<Integer> ans = rangeMinQuery(arr, queries);

        for (int x : ans) {
            System.out.print(x + " ");
        }
    }
}
Python
tree = []


def build(arr, node, start, end):
    if start == end:
        tree[node] = arr[start]
        return

    mid = start + (end - start) // 2

    build(arr, 2 * node + 1, start, mid)
    build(arr, 2 * node + 2, mid + 1, end)

    tree[node] = min(tree[2 * node + 1], tree[2 * node + 2])


def query(node, start, end, l, r):
    # No overlap
    if r < start or end < l:
        return float('inf')

    # Complete overlap
    if l <= start and end <= r:
        return tree[node]

    mid = start + (end - start) // 2

    left_min = query(2 * node + 1, start, mid, l, r)
    right_min = query(2 * node + 2, mid + 1, end, l, r)

    return min(left_min, right_min)


def rangeMinQuery(arr, queries):
    global tree

    n = len(arr)
    tree = [0] * (4 * n)

    # Build the segment tree
    build(arr, 0, 0, n - 1)

    ans = []

    # Process each query
    for l, r in queries:
        ans.append(query(0, 0, n - 1, l, r))

    return ans


if __name__ == "__main__":
    arr = [1, 2, 3, 4]
    queries = [[0, 2], [2, 3]]

    ans = rangeMinQuery(arr, queries)

    print(*ans)
C#
using System;
using System.Collections.Generic;

public class GFG
{
    private int[] tree;

    private void Build(int[] arr, int node, int start, int end)
    {
        if (start == end)
        {
            tree[node] = arr[start];
            return;
        }

        int mid = start + (end - start) / 2;

        Build(arr, 2 * node + 1, start, mid);
        Build(arr, 2 * node + 2, mid + 1, end);

        tree[node] = Math.Min(
            tree[2 * node + 1],
            tree[2 * node + 2]
        );
    }

    private int Query(int node, int start, int end, int l, int r)
    {
        // No overlap
        if (r < start || end < l)
            return int.MaxValue;

        // Complete overlap
        if (l <= start && end <= r)
            return tree[node];

        int mid = start + (end - start) / 2;

        int leftMin = Query(2 * node + 1, start, mid, l, r);
        int rightMin = Query(2 * node + 2, mid + 1, end, l, r);

        return Math.Min(leftMin, rightMin);
    }

    public List<int> rangeMinQuery(int[] arr, int[][] queries)
    {
        int n = arr.Length;

        tree = new int[4 * n];

        // Build the segment tree
        Build(arr, 0, 0, n - 1);

        List<int> ans = new List<int>();

        // Process each query
        foreach (int[] q in queries)
        {
            ans.Add(Query(0, 0, n - 1, q[0], q[1]));
        }

        return ans;
    }

    static void Main()
    {
        int[] arr = { 1, 2, 3, 4 };

        int[][] queries =
        {
            new int[] { 0, 2 },
            new int[] { 2, 3 }
        };

        GFG obj = new GFG();

        List<int> ans = obj.rangeMinQuery(arr, queries);


        for (int i = 0; i < ans.Count; i++)
        {
            Console.Write(ans[i]);

            if (i < ans.Count - 1)
                Console.Write(", ");
        }

    }
}
JavaScript
function build(arr, tree, node, start, end) {
    if (start === end) {
        tree[node] = arr[start];
        return;
    }

    const mid = start + Math.floor((end - start) / 2);

    build(arr, tree, 2 * node + 1, start, mid);
    build(arr, tree, 2 * node + 2, mid + 1, end);

    tree[node] = Math.min(
        tree[2 * node + 1],
        tree[2 * node + 2]
    );
}

function query(tree, node, start, end, l, r) {
    // No overlap
    if (r < start || end < l) {
        return Infinity;
    }

    // Complete overlap
    if (l <= start && end <= r) {
        return tree[node];
    }

    const mid = start + Math.floor((end - start) / 2);

    const leftMin = query(
        tree, 2 * node + 1, start, mid, l, r
    );

    const rightMin = query(
        tree, 2 * node + 2, mid + 1, end, l, r
    );

    return Math.min(leftMin, rightMin);
}

function rangeMinQuery(arr, queries) {
    const n = arr.length;
    const tree = new Array(4 * n).fill(Infinity);

    // Build the segment tree
    build(arr, tree, 0, 0, n - 1);

    const ans = [];

    // Process each query
    for (const q of queries) {
        ans.push(
            query(tree, 0, 0, n - 1, q[0], q[1])
        );
    }

    return ans;
}

// Driver Code
const arr = [1, 2, 3, 4, 5];

const queries = [
    [0, 2],
    [2, 4]
];

const ans = rangeMinQuery(arr, queries);

console.log(ans.join(", "));

Output
1 3 

Further read  
https://www.geeksforgeeks.org/dsa/range-minimum-query-for-static-array/ 

Comment