📌  相关文章
📜  在给定的查询范围内找到在给定范围内具有最大设置位的元素

📅  最后修改于: 2021-04-26 08:18:36             🧑  作者: Mango

给定一个由N个整数和Q个查询组成的数组arr [] ,每个查询具有两个整数LR ,任务是找到具有最大设置位在L到R范围内的元素。

注意:如果有多个具有最大设置位的元素,则打印最大的那些位。

例子:

天真的方法:一个简单的解决方案是运行一个从L到R的循环,计算每个元素的设置位的数量,并为每个查询找到从L到R的最大设置位元素。

时间复杂度:O(Q * N)
辅助空间复杂度:O(1)

高效方法:想法是使用段树,其中每个节点包含两个值,即具有最大设置位的元素和最大设置位的计数。

  • 段树的表示形式:
    1. 叶节点是给定数组的元素。
    2. 每个内部节点代表叶节点的一些合并。对于不同的问题,合并可能会有所不同。对于此问题,在一个节点下合并最大的叶子的max_set_bits。
    3. 树的数组表示形式用于表示段树。对于索引i处的每个节点,左子节点在索引2 * i + 1处,右子节点在索引2 * i + 2处,父节点在(i-1)/ 2处
  • 从给定数组构造细分树:
    1. 我们从一个段arr [0开始。 。 。 n-1]。并每次将当前段分为两半(如果尚未将其变为长度为1的段),然后在两个半段上调用相同的过程,则对于每个这样的段,我们将max_set_bits和值存储在对应的节点。
    2. 任何两个范围组合的最大设置位将是左侧的最大设置位或右侧的最大设置位,以最大值为准。
    3. 最后,在细分树上计算范围查询。

下面是上述方法的实现:

C++
// C++ implementation to find
// maximum set bits value in a range
 
#include 
 
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;
}


Java
// 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


Python3
# Python3 implementation to find
# maximum set bits value in a range
 
# Structure to store two
# values in one node
from typing import List
 
class Node:
     
    def __init__(self) -> None:
         
        self.value = 0
        self.max_set_bits = 0
 
tree = [Node() for _ in range(4 * 10000)]
 
# Function that returns the count
# of set bits in a number
def setBits(x: int) -> int:
     
    # Parity will store the
    # count of set bits
    parity = 0
     
    while (x != 0):
        if (x & 1):
            parity += 1
             
        x = x >> 1
 
    return parity
 
# Function to build the segment tree
def buildSegmentTree(a: List[int], index: int,
                     beg: int, end: int) -> None:
 
    # 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:
        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
 
        elif (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
def query(index: int, beg: int,
          end: int, l: int, r: int) -> Node:
 
    result = 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 or 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 and end <= r):
        return tree[index]
 
    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
    left = query(2 * index + 1, beg, mid, l, r)
    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
 
    elif (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
if __name__ == "__main__":
 
    a = [ 18, 9, 8, 15, 14, 5 ]
 
    # Calculates the length of array
    N = len(a)
 
    # Build Segment Tree
    buildSegmentTree(a, 0, 0, N - 1)
 
    # Find the max set bits value between
    # 1st and 4th index of array
    print(query(0, 0, N - 1, 1, 4).value)
 
    # Find the max set bits value between
    # 0th and 2nd index of array
    print(query(0, 0, N - 1, 0, 2).value)
 
# This code is contributed by sanjeev2552


C#
// 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


输出:
15
18

时间复杂度: O(Q * logN)