Find the element having maximum set bits in the given range for Q queries

Given an array arr[] of N integers and Q queries, each query having two integers L and R, the task is to find the element having maximum set bits in the range L to R. 
Note: If there are multiple elements having maximum set bits, then print the maximum of those.
Examples: 
 

Input: arr[] = {18, 9, 8, 15, 14, 5}, Q = {{1, 4}} 
Output: 15 
Explanation: 
Subarray – {9, 8, 15, 14} 
Binary Representation of these integers – 
9 => 1001 => Set Bits = 2 
8 => 1000 => Set Bits = 1 
15 => 1111 => Set Bits = 4 
14 => 1110 => Set Bits = 3 
Therefore, element with maximum set bits is 15.
Input: arr[] = {18, 9, 8, 15, 14, 5}, Q = {{0, 2}} 
Output: 18 
Explanation: 
Subarray – {18, 9, 8} 
Binary Representation of these integers – 
18 => 10010 => Set Bits = 2 
9 => 1001 => Set Bits = 2 
8 => 1000 => Set Bits = 1 
Therefore, element with maximum set bits is maximum of 18 and 9, which is 18. 
 

 

Naive Approach: A simple solution is to run a loop from L to R and calculate the number of set bits for each element and find the maximum set bits element from L to R for every query.
Time Complexity: O(Q * N) 
Auxiliary Space Complexity: O(1)
Efficient Approach: The idea is to use Segment tree, where each node contains two values, element with maximum set bits and count of maximum set bits. 
 

  • Representation of Segment trees: 
    1. Leaf Nodes are the elements of the given array. 
       
    2. Each internal node represents some merging of the leaf nodes. The merging may be different for different problems. For this problem, merging is maximum of the max_set_bits of leaves under a node. 
       
    3. An array representation of tree is used to represent Segment Trees. For each node at index i, the left child is at index 2*i+1, right child at 2*i+2 and the parent is at (i-1)/2
       
  • Construction of Segment Tree from given array: 
    1. We start with a segment arr[0 . . . n-1]. and every time we divide the current segment into two halves(if it has not yet become a segment of length 1), and then call the same procedure on both halves, and for each such segment, we store the max_set_bits and the value in the corresponding node. 
       
    2. The maximum set bits for any two range combining will either be the maximum set bits from the left side or the maximum set bits from the right side, whichever is maximum will be taken into account. 
       
    3. Finally, compute the range query on the segment tree
       

Below is the implementation of the above approach:
 



C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation to find
// maximum set bits value in a range
  
#include <bits/stdc++.h>
  
using namespace std;
  
// Structure to store two
// values in one node
struct Node {
    int value;
    int max_set_bits;
};
  
Node tree[4 * 10000];
  
// Function that returns the count
// of set bits in a number
int setBits(int x)
{
    // Parity will store the
    // count of set bits
    int parity = 0;
    while (x != 0) {
        if (x & 1)
            parity++;
        x = x >> 1;
    }
    return parity;
}
  
// Function to build the segment tree
void buildSegmentTree(int a[], int index,
                      int beg, int end)
{
  
    // Condition to check if there is
    // only one element in the array
    if (beg == end) {
        tree[index].value = a[beg];
        tree[index].max_set_bits
            = setBits(a[beg]);
    }
  
    else {
  
        int mid = (beg + end) / 2;
  
        // If there are more than one elements,
        // then recur for left and right subtrees
        buildSegmentTree(a, 2 * index + 1,
                         beg, mid);
        buildSegmentTree(a, 2 * index + 2,
                         mid + 1, end);
  
        // Condition to check the maximum set
        // bits is greater in two subtrees
        if (tree[2 * index + 1].max_set_bits
            > tree[2 * index + 2].max_set_bits) {
  
            tree[index].max_set_bits
                = tree[2 * index + 1]
                      .max_set_bits;
            tree[index].value
                = tree[2 * index + 1]
                      .value;
        }
  
        else if (tree[2 * index + 2].max_set_bits
                 > tree[2 * index + 1].max_set_bits) {
  
            tree[index].max_set_bits
                = tree[2 * index + 2]
                      .max_set_bits;
            tree[index].value
                = tree[2 * index + 2].value;
        }
  
        // Condition when maximum set bits
        // are equal in both subtrees
        else {
            tree[index].max_set_bits
                = tree[2 * index + 2]
                      .max_set_bits;
            tree[index].value = max(
                tree[2 * index + 2].value,
                tree[2 * index + 1].value);
        }
    }
}
  
// Function to do the range query
// in the segment tree
Node query(int index, int beg,
           int end, int l, int r)
{
    Node result;
    result.value
        = result.max_set_bits = -1;
  
    // If segment of this node is outside the given
    // range, then return the minimum value.
    if (beg > r || end < l)
        return result;
  
    // If segment of this node is a part of given
    // range, then return the node of the segment
    if (beg >= l && end <= r)
        return tree[index];
  
    int mid = (beg + end) / 2;
  
    // If left segment of this node falls out of
    // range, then recur in the right side of
    // the tree
    if (l > mid)
        return query(2 * index + 2, mid + 1,
                     end, l, r);
  
    // If right segment of this node falls out of
    // range, then recur in the left side of
    // the tree
    if (r <= mid)
        return query(2 * index + 1, beg,
                     mid, l, r);
  
    // If a part of this segment overlaps with
    // the given range
    Node left = query(2 * index + 1, beg,
                      mid, l, r);
    Node right = query(2 * index + 2, mid + 1,
                       end, l, r);
  
    if (left.max_set_bits > right.max_set_bits) {
        result.max_set_bits = left.max_set_bits;
        result.value = left.value;
    }
    else if (right.max_set_bits > left.max_set_bits) {
        result.max_set_bits = right.max_set_bits;
        result.value = right.value;
    }
    else {
        result.max_set_bits = left.max_set_bits;
        result.value = max(right.value, left.value);
    }
  
    // Returns the value
    return result;
}
  
// Driver code
int main()
{
  
    int a[] = { 18, 9, 8, 15, 14, 5 };
  
    // Calculates the length of array
    int N = sizeof(a) / sizeof(a[0]);
  
    // Build Segment Tree
    buildSegmentTree(a, 0, 0, N - 1);
  
    // Find the max set bits value between
    // 1st and 4th index of array
    cout << query(0, 0, N - 1, 1, 4).value
         << endl;
  
    // Find the max set bits value between
    // 0th and 2nd index of array
    cout << query(0, 0, N - 1, 0, 2).value
         << endl;
  
    return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation to find
// maximum set bits value in a range
import java.util.*;
  
class GFG{
  
// Structure to store two
// values in one node
static class Node 
{
    int value;
    int max_set_bits;
};
  
static Node []tree = new Node[4 * 10000];
  
// Function that returns the count
// of set bits in a number
static int setBits(int x)
{
      
    // Parity will store the
    // count of set bits
    int parity = 0;
    while (x != 0
    {
        if (x % 2 == 1)
            parity++;
        x = x >> 1;
    }
    return parity;
}
  
// Function to build the segment tree
static void buildSegmentTree(int a[], int index,
                             int beg, int end)
{
      
    // Condition to check if there is
    // only one element in the array
    if (beg == end) 
    {
        tree[index].value = a[beg];
        tree[index].max_set_bits = setBits(a[beg]);
    }
    else
    {
        int mid = (beg + end) / 2;
  
        // If there are more than one elements,
        // then recur for left and right subtrees
        buildSegmentTree(a, 2 * index + 1,
                         beg, mid);
        buildSegmentTree(a, 2 * index + 2,
                          mid + 1, end);
  
        // Condition to check the maximum set
        // bits is greater in two subtrees
        if (tree[2 * index + 1].max_set_bits >
            tree[2 * index + 2].max_set_bits) 
        {
            tree[index].max_set_bits = 
            tree[2 * index + 1].max_set_bits;
            tree[index].value = 
            tree[2 * index + 1].value;
        }
        else if (tree[2 * index + 2].max_set_bits > 
                 tree[2 * index + 1].max_set_bits) 
        {
            tree[index].max_set_bits =
            tree[2 * index + 2].max_set_bits;
            tree[index].value =
            tree[2 * index + 2].value;
        }
  
        // Condition when maximum set bits
        // are equal in both subtrees
        else
        {
            tree[index].max_set_bits =
            tree[2 * index + 2].max_set_bits;
            tree[index].value = Math.max(
            tree[2 * index + 2].value,
            tree[2 * index + 1].value);
        }
    }
}
  
// Function to do the range query
// in the segment tree
static Node query(int index, int beg,
                  int end, int l, int r)
{
    Node result = new Node();
    result.value = result.max_set_bits = -1;
  
    // If segment of this node is outside the given
    // range, then return the minimum value.
    if (beg > r || end < l)
        return result;
  
    // If segment of this node is a part of given
    // range, then return the node of the segment
    if (beg >= l && end <= r)
        return tree[index];
  
    int mid = (beg + end) / 2;
  
    // If left segment of this node falls out of
    // range, then recur in the right side of
    // the tree
    if (l > mid)
        return query(2 * index + 2, mid + 1,
                         end, l, r);
  
    // If right segment of this node falls out of
    // range, then recur in the left side of
    // the tree
    if (r <= mid)
        return query(2 * index + 1, beg,
                     mid, l, r);
  
    // If a part of this segment overlaps with
    // the given range
    Node left = query(2 * index + 1, beg,
                          mid, l, r);
    Node right = query(2 * index + 2, mid + 1,
                           end, l, r);
  
    if (left.max_set_bits > right.max_set_bits) 
    {
        result.max_set_bits = left.max_set_bits;
        result.value = left.value;
    }
    else if (right.max_set_bits > left.max_set_bits)
    {
        result.max_set_bits = right.max_set_bits;
        result.value = right.value;
    }
    else 
    {
        result.max_set_bits = left.max_set_bits;
        result.value = Math.max(right.value, 
                                left.value);
    }
  
    // Returns the value
    return result;
}
  
// Driver code
public static void main(String[] args)
{
  
    int a[] = { 18, 9, 8, 15, 14, 5 };
  
    // Calculates the length of array
    int N = a.length;
      
    for(int i = 0; i < tree.length; i++)
        tree[i] = new Node();
          
    // Build Segment Tree
    buildSegmentTree(a, 0, 0, N - 1);
  
    // Find the max set bits value between
    // 1st and 4th index of array
    System.out.print(query(0, 0, N - 1, 1, 4).value +"\n");
  
    // Find the max set bits value between
    // 0th and 2nd index of array
    System.out.print(query(0, 0, N - 1, 0, 2).value +"\n");
}
}
  
// This code is contributed by amal kumar choubey

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# implementation to find maximum
// set bits value in a range 
using System;
  
class GFG{ 
  
// Structure to store two 
// values in one node 
class Node 
    public int value; 
    public int max_set_bits; 
}; 
  
static Node []tree = new Node[4 * 10000]; 
  
// Function that returns the count 
// of set bits in a number 
static int setBits(int x) 
      
    // Parity will store the 
    // count of set bits 
    int parity = 0; 
    while (x != 0) 
    
        if (x % 2 == 1) 
            parity++; 
        x = x >> 1; 
    
    return parity; 
  
// Function to build the segment tree 
static void buildSegmentTree(int []a, int index, 
                             int beg, int end) 
      
    // Condition to check if there is 
    // only one element in the array 
    if (beg == end) 
    
        tree[index].value = a[beg]; 
        tree[index].max_set_bits = setBits(a[beg]); 
    
    else
    
        int mid = (beg + end) / 2; 
  
        // If there are more than one elements, 
        // then recur for left and right subtrees 
        buildSegmentTree(a, 2 * index + 1, 
                         beg, mid); 
        buildSegmentTree(a, 2 * index + 2, 
                         mid + 1, end); 
  
        // Condition to check the maximum set 
        // bits is greater in two subtrees 
        if (tree[2 * index + 1].max_set_bits > 
            tree[2 * index + 2].max_set_bits) 
        
            tree[index].max_set_bits = 
            tree[2 * index + 1].max_set_bits; 
            tree[index].value = 
            tree[2 * index + 1].value; 
        
        else if (tree[2 * index + 2].max_set_bits > 
                 tree[2 * index + 1].max_set_bits) 
        
            tree[index].max_set_bits = 
            tree[2 * index + 2].max_set_bits; 
            tree[index].value = 
            tree[2 * index + 2].value; 
        
  
        // Condition when maximum set bits 
        // are equal in both subtrees 
        else
        
            tree[index].max_set_bits = 
            tree[2 * index + 2].max_set_bits; 
            tree[index].value = Math.Max( 
            tree[2 * index + 2].value, 
            tree[2 * index + 1].value); 
        
    
  
// Function to do the range query 
// in the segment tree 
static Node query(int index, int beg, 
                  int end, int l, int r) 
    Node result = new Node(); 
    result.value = result.max_set_bits = -1; 
  
    // If segment of this node is outside the given 
    // range, then return the minimum value. 
    if (beg > r || end < l) 
        return result; 
  
    // If segment of this node is a part of given 
    // range, then return the node of the segment 
    if (beg >= l && end <= r) 
        return tree[index]; 
  
    int mid = (beg + end) / 2; 
  
    // If left segment of this node falls out of 
    // range, then recur in the right side of 
    // the tree 
    if (l > mid) 
        return query(2 * index + 2, mid + 1, 
                         end, l, r); 
  
    // If right segment of this node falls out of 
    // range, then recur in the left side of 
    // the tree 
    if (r <= mid) 
        return query(2 * index + 1, beg, 
                         mid, l, r); 
  
    // If a part of this segment overlaps with 
    // the given range 
    Node left = query(2 * index + 1, beg, 
                          mid, l, r); 
    Node right = query(2 * index + 2, mid + 1, 
                           end, l, r); 
  
    if (left.max_set_bits > right.max_set_bits) 
    
        result.max_set_bits = left.max_set_bits; 
        result.value = left.value; 
    
    else if (right.max_set_bits > left.max_set_bits) 
    
        result.max_set_bits = right.max_set_bits; 
        result.value = right.value; 
    
    else
    
        result.max_set_bits = left.max_set_bits; 
        result.value = Math.Max(right.value, 
                                 left.value); 
    
  
    // Returns the value 
    return result; 
  
// Driver code 
public static void Main(String[] args) 
  
    int []a = { 18, 9, 8, 15, 14, 5 }; 
  
    // Calculates the length of array 
    int N = a.Length; 
      
    for(int i = 0; i < tree.Length; i++) 
        tree[i] = new Node(); 
          
    // Build Segment Tree 
    buildSegmentTree(a, 0, 0, N - 1); 
  
    // Find the max set bits value between 
    // 1st and 4th index of array 
    Console.Write(query(0, 0, N - 1, 1, 4).value + "\n"); 
  
    // Find the max set bits value between 
    // 0th and 2nd index of array 
    Console.Write(query(0, 0, N - 1, 0, 2).value + "\n"); 
  
// This code is contributed by amal kumar choubey 

chevron_right


Output: 

15
18

Time Complexity: O(Q * logN)
 

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

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.



Improved By : Amal Kumar Choubey