给定一个由N个整数和Q个查询组成的数组arr [] 。每个查询可以由两个整数L和R表示。任务是在子数组arr [L]至arr [R]中找到不同整数的计数。
例子:
Input: arr[] = {1, 1, 3, 3, 5, 5, 7, 7, 9, 9 }, L = 0, R = 4
Output: 3
Input: arr[] = { 1, 1, 2, 1, 3 }, L = 1, R = 3
Output : 2
天真的方法:在这种方法中,我们将遍历范围l,r,并使用一组来查找范围中的所有不同元素并将其打印出来。
时间复杂度: O(q * n)
高效方法:想法是形成一个段树,节点将在其中存储范围内的所有不同元素。为此,我们可以在C++中使用自平衡BST或“设置”数据结构。
每个查询将返回集合的大小。
下面是上述方法的实现:
C++
// C++ implementation of above approach
#include
using namespace std;
// Each segment of the segment tree would be a set
// to maintain distinct elements
set* segment;
// Build the segment tree
// i denotes current node, s denotes start and
// e denotes the end of range for current node
void build(int i, int s, int e, int arr[])
{
// If start is equal to end then
// insert the array element
if (s == e) {
segment[i].insert(arr[s]);
return;
}
// Else divide the range into two halves
// (start to mid) and (mid+1 to end)
// first half will be the left node
// and the second half will be the right node
build(2 * i, s, (s + e) / 2, arr);
build(1 + 2 * i, 1 + (s + e) / 2, e, arr);
// Insert the sets of right and left
// node of the segment tree
segment[i].insert(segment[2 * i].begin(),
segment[2 * i].end());
segment[i].insert(segment[2 * i + 1].begin(),
segment[2 * i + 1].end());
}
// Query in an range a to b
set query(int node, int l, int r, int a, int b)
{
set left, right, result;
// If the range is out of the bounds
// of this segment
if (b < l || a > r)
return result;
// If the range lies in this segment
if (a <= l && r <= b)
return segment[node];
// Else query for the right and left
// leaf node of this subtree
// and insert them into the set
left = query(2 * node, l, (l + r) / 2, a, b);
result.insert(left.begin(), left.end());
right = query(1 + 2 * node, 1 + (l + r) / 2, r, a, b);
result.insert(right.begin(), right.end());
// Return the result
return result;
}
// Initialize the segment tree
void init(int n)
{
// Get the height of the segment tree
int h = (int)ceil(log2(n));
h = (2 * (pow(2, h))) - 1;
// Initialize the segment tree
segment = new set[h];
}
// Function to get the result for the
// subarray from arr[l] to arr[r]
void getDistinct(int l, int r, int n)
{
// Query for the range set
set ans = query(1, 0, n - 1, l, r);
cout << ans.size() << endl;
}
// Driver code
int main()
{
int arr[] = { 1, 1, 2, 1, 3 };
int n = sizeof(arr) / sizeof(arr[0]);
init(n);
// Bulid the segment tree
build(1, 0, n - 1, arr);
// Query in range 0 to 4
getDistinct(0, 4, n);
return 0;
}
Java
// Java implementation of above approach
import java.io.*;
import java.util.*;
class GFG
{
// Each segment of the segment tree would be a set
// to maintain distinct elements
static HashSet[] segment;
// Build the segment tree
// i denotes current node, s denotes start and
// e denotes the end of range for current node
static void build(int i, int s, int e, int[] arr)
{
// If start is equal to end then
// insert the array element
if (s == e)
{
segment[i].add(arr[s]);
return;
}
// Else divide the range into two halves
// (start to mid) and (mid+1 to end)
// first half will be the left node
// and the second half will be the right node
build(2 * i, s, (s + e) / 2, arr);
build(1 + 2 * i, 1 + (s + e) / 2, e, arr);
// Insert the sets of right and left
// node of the segment tree
segment[i].addAll(segment[2 * i]);
segment[i].addAll(segment[2 * i + 1]);
}
// Query in an range a to b
static HashSet query(int node, int l,
int r, int a, int b)
{
HashSet left = new HashSet<>();
HashSet right = new HashSet<>();
HashSet result = new HashSet<>();
// If the range is out of the bounds
// of this segment
if (b < l || a > r)
return result;
// If the range lies in this segment
if (a <= l && r <= b)
return segment[node];
// Else query for the right and left
// leaf node of this subtree
// and insert them into the set
left = query(2 * node, l, (l + r) / 2, a, b);
result.addAll(left);
right = query(1 + 2 * node, 1 + (l + r) / 2, r, a, b);
result.addAll(right);
// Return the result
return result;
}
// Initialize the segment tree
@SuppressWarnings("unchecked")
static void init(int n)
{
// Get the height of the segment tree
int h = (int) Math.ceil(Math.log(n) / Math.log(2));
h = (int) (2 * Math.pow(2, h)) - 1;
// Initialize the segment tree
segment = new HashSet[h];
for (int i = 0; i < h; i++)
segment[i] = new HashSet<>();
}
// Function to get the result for the
// subarray from arr[l] to arr[r]
static void getDistinct(int l, int r, int n)
{
// Query for the range set
HashSet ans = query(1, 0, n - 1, l, r);
System.out.println(ans.size());
}
// Driver Code
public static void main(String[] args)
{
int[] arr = { 1, 1, 2, 1, 3 };
int n = arr.length;
init(n);
// Bulid the segment tree
build(1, 0, n - 1, arr);
// Query in range 0 to 4
getDistinct(0, 4, n);
}
}
// This code is contributed by
// sanjeev2552
Python3
# python3 implementation of above approach
from math import ceil,log,floor
# Each segment of the segment tree would be a set
# to maintain distinct elements
segment=[[] for i in range(1000)]
# Build the segment tree
# i denotes current node, s denotes start and
# e denotes the end of range for current node
def build(i, s, e, arr):
# If start is equal to end then
# append the array element
if (s == e):
segment[i].append(arr[s])
return
# Else divide the range into two halves
# (start to mid) and (mid+1 to end)
# first half will be the left node
# and the second half will be the right node
build(2 * i, s, (s + e) // 2, arr)
build(1 + 2 * i, 1 + (s + e) // 2, e, arr)
# Insert the sets of right and left
# node of the segment tree
segment[i].append(segment[2 * i])
segment[i].append(segment[2 * i + 1])
# Query in an range a to b
def query(node, l, r, a, b):
left, right, result=[],[],[]
# If the range is out of the bounds
# of this segment
if (b < l or a > r):
return result
# If the range lies in this segment
if (a <= l and r <= b):
return segment[node]
# Else query for the right and left
# leaf node of this subtree
# and append them into the set
left = query(2 * node, l, (l + r) // 2, a, b)
result.append(left)
right = query(1 + 2 * node, 1 + (l + r) // 2, r, a, b)
result.append(right)
# Return the result
return result
def answer(ans):
d = {}
for i in str(ans):
if i not in ['[',',',']',' ']:
d[i]=1
return len(d)
# Initialize the segment tree
def init(n):
# Get the height of the segment tree
h = ceil(log(n, 2))
h = (2 * (pow(2, h))) - 1
# Function to get the result for the
# subarray from arr[l] to arr[r]
def getDistinct(l, r, n):
# Query for the range set
ans = query(1, 0, n - 1, l, r)
print(answer(str(ans)))
# Driver code
arr=[1, 1, 2, 1, 3]
n = len(arr)
init(n)
# Bulid the segment tree
build(1, 0, n - 1, arr)
# Query in range 0 to 4
getDistinct(0, 4, n)
# This code is contributed by mohit kumar 29
C#
// C# implementation of
// the above approach
using System;
using System.Collections;
using System.Collections.Generic;
class GFG{
// Each segment of the segment
// tree would be a set to maintain
// distinct elements
static HashSet[] segment;
// Build the segment tree
// i denotes current node,
// s denotes start and
// e denotes the end of
// range for current node
static void build(int i, int s,
int e, int[] arr)
{
// If start is equal to end then
// insert the array element
if (s == e)
{
segment[i].Add(arr[s]);
return;
}
// Else divide the range
// into two halves (start
// to mid) and (mid+1 to end)
// first half will be the left
// node and the second half
// will be the right node
build(2 * i, s,
(s + e) / 2, arr);
build(1 + 2 * i,
1 + (s + e) / 2,
e, arr);
// Insert the sets of
// right and left node
// of the segment tree
foreach(int x in segment[2 * i])
{
segment[i].Add(x);
}
foreach(int x in segment[2 * i + 1])
{
segment[i].Add(x);
}
}
// Query in an range a to b
static HashSet query(int node, int l,
int r, int a, int b)
{
HashSet left = new HashSet();
HashSet right = new HashSet();
HashSet result = new HashSet();
// If the range is out
// of the bounds
// of this segment
if (b < l || a > r)
return result;
// If the range lies
// in this segment
if (a <= l && r <= b)
return segment[node];
// Else query for the right and left
// leaf node of this subtree
// and insert them into the set
left = query(2 * node,
l, (l + r) / 2,
a, b);
foreach(int x in left)
{
result.Add(x);
}
right = query(1 + 2 * node,
1 + (l + r) / 2,
r, a, b);
foreach(int x in right)
{
result.Add(x);
}
// Return the result
return result;
}
// Initialize the segment tree
static void init(int n)
{
// Get the height of the segment tree
int h = (int) Math.Ceiling(Math.Log(n) /
Math.Log(2));
h = (int) (2 * Math.Pow(2, h)) - 1;
// Initialize the segment tree
segment = new HashSet[h];
for (int i = 0; i < h; i++)
segment[i] = new HashSet();
}
// Function to get the result for the
// subarray from arr[l] to arr[r]
static void getDistinct(int l,
int r, int n)
{
// Query for the range set
HashSet ans = query(1, 0,
n - 1,
l, r);
Console.Write(ans.Count);
}
// Driver Code
public static void Main(string[] args)
{
int[] arr = {1, 1, 2, 1, 3};
int n = arr.Length;
init(n);
// Bulid the segment tree
build(1, 0, n - 1, arr);
// Query in range 0 to 4
getDistinct(0, 4, n);
}
}
// This code is contributed by rutvik_56
输出:
3
时间复杂度: O(q * n * log(n))