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

📅  最后修改于: 2021-09-16 11:15:50             🧑  作者: 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)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程