查询以检查范围是否由连续元素组成
给定一个由n 个不连续整数组成的数组和Q个查询,任务是检查给定范围l和r的元素是否连续。
例子:
Input: arr = { 2, 4, 3, 7, 6, 1}, Q = { (1, 3), (3, 5), (5, 6) }
Output: Yes, No, No
Explanation: Array elements from (1, 3) = {2, 4, 3}, (3, 5) = {3, 7, 6}, (5, 6) = {6, 1}
So the answer is Yes, No, No
Input: arr = {1, 2, 3, 4, 5}, Q = { (1, 2), (4, 5), (1, 5) }
Output:Yes, Yes, Yes
天真的方法:
可以对范围l和r之间的子数组进行排序并检查它是否包含连续元素。
时间复杂度: O(q*n*log n)
其中 n 是数组的大小,q 是查询的数量。
有效的方法:
- 段树可用于获取范围内的最小值和最大值。
- 如果子数组的最小元素是 x,最大元素是 y,那么我们可以不存在小于 x 且大于 y 的元素,所以我们可以说x<=arr[i]<=y 。
- 由于没有重复的元素,因此可以得出结论,如果最大和最小元素的差+1等于范围的长度(r-l+1),则范围由连续的元素组成。
下面是上述方法的实现。
CPP
// C++ implementation of the above approach.
#include
using namespace std;
// Segment tree
int tree_min[1000001],
tree_max[1000001];
// Functions to return
// minimum and maximum
int min(int a, int b)
{
return a < b ? a : b;
}
int max(int a, int b)
{
return a > b ? a : b;
}
// Segment tree for minimum element
void build_min(int array[], int node,
int left, int right)
{
// If left is equal to right
if (left == right)
tree_min[node] = array[left];
else {
// Divide the segment into equal halves
build_min(array, 2 * node, left,
(left + right) / 2);
build_min(array, 2 * node + 1,
(left + right) / 2 + 1, right);
// Update the element as minimum
// of the divided two subarrays
tree_min[node] = min(tree_min[2 * node],
tree_min[2 * node + 1]);
}
}
// Query to find a minimum
// in a given ranges
int query_min(int node, int c_l,
int c_r, int l, int r)
{
// Out of range
if (c_l > r || c_r < l)
return 1e9;
// Within the range completely
if (c_l >= l && c_r <= r)
return tree_min[node];
else
// Divide the range into two halves
// Query for each half
// and return the minimum of two
return min(query_min(2 * node, c_l,
(c_l + c_r) / 2, l, r),
query_min(2 * node + 1,
(c_l + c_r) / 2 + 1,
c_r, l, r));
}
// Segment tree for maximum element
void build_max(int array[], int node,
int left, int right)
{
// If left is equal to right
if (left == right)
tree_max[node] = array[left];
else {
// Divide the segment into equal halves
build_max(array, 2 * node, left,
(left + right) / 2);
build_max(array, 2 * node + 1,
(left + right) / 2 + 1, right);
// Update the element as maximum
// of the divided two subarrays
tree_max[node] = max(tree_max[2 * node],
tree_max[2 * node + 1]);
}
}
// Query to find maximum
// in a given ranges
int query_max(int node, int c_l,
int c_r, int l, int r)
{
// Out of range
if (c_l > r || c_r < l)
return -1;
// Within the range completely
if (c_l >= l && c_r <= r)
return tree_max[node];
else
// Divide the range into two halves
// and query for each half
// and return the maximum of two
return max(query_max(2 * node, c_l,
(c_l + c_r) / 2, l, r),
query_max(2 * node + 1,
(c_l + c_r) / 2 + 1,
c_r, l, r));
}
// Build the tree
void init(int array[], int n)
{
build_min(array, 1, 0, n - 1);
build_max(array, 1, 0, n - 1);
}
// Check if the given range is Consecutive
bool isConsecutive(int x, int y, int n)
{
return ((query_max(1, 0, n - 1, x, y)
- query_min(1, 0, n - 1, x, y))
== (y - x));
}
// Driver code
int main()
{
int arr[] = { 2, 4, 3, 7, 6, 1 };
int query[][2] = { { 1, 3 }, { 3, 5 }, { 5, 6 } };
int n = sizeof(arr) / sizeof(int), q = 3;
init(arr, n);
for (int i = 0; i < q; i++) {
int l, r;
l = query[i][0];
r = query[i][1];
cout << (isConsecutive(l - 1, r - 1, n) ?
"Yes" : "No") << "\n";
}
return 0;
}
Java
// Java implementation of the above approach.
class GFG
{
// Segment tree
static int[] tree_min = new int[1000001];
static int[] tree_max = new int[1000001];
// Functions to return
// minimum and maximum
static int min(int a, int b)
{
return a < b ? a : b;
}
static int max(int a, int b)
{
return a > b ? a : b;
}
// Segment tree for minimum element
static void build_min(int array[], int node, int left, int right)
{
// If left is equal to right
if (left == right)
tree_min[node] = array[left];
else
{
// Divide the segment into equal halves
build_min(array, 2 * node, left, (left + right) / 2);
build_min(array, 2 * node + 1,
(left + right) / 2 + 1, right);
// Update the element as minimum
// of the divided two subarrays
tree_min[node] = Math.min(tree_min[2 * node],
tree_min[2 * node + 1]);
}
}
// Query to find a minimum
// in a given ranges
static int query_min(int node, int c_l, int c_r, int l, int r)
{
// Out of range
if (c_l > r || c_r < l)
return (int) 1e9;
// Within the range completely
if (c_l >= l && c_r <= r)
return tree_min[node];
else
// Divide the range into two halves
// Query for each half
// and return the minimum of two
return min(query_min(2 * node, c_l, (c_l + c_r) / 2, l, r),
query_min(2 * node + 1, (c_l + c_r) / 2 + 1, c_r, l, r));
}
// Segment tree for maximum element
static void build_max(int array[], int node, int left, int right)
{
// If left is equal to right
if (left == right)
tree_max[node] = array[left];
else
{
// Divide the segment into equal halves
build_max(array, 2 * node, left, (left + right) / 2);
build_max(array, 2 * node + 1, (left + right) / 2 + 1, right);
// Update the element as maximum
// of the divided two subarrays
tree_max[node] = Math.max(tree_max[2 * node],
tree_max[2 * node + 1]);
}
}
// Query to find maximum
// in a given ranges
static int query_max(int node, int c_l, int c_r, int l, int r)
{
// Out of range
if (c_l > r || c_r < l)
return -1;
// Within the range completely
if (c_l >= l && c_r <= r)
return tree_max[node];
else
// Divide the range into two halves
// and query for each half
// and return the maximum of two
return Math.max(query_max(2 * node, c_l, (c_l + c_r) / 2, l, r),
query_max(2 * node + 1, (c_l + c_r) / 2 + 1, c_r, l, r));
}
// Build the tree
static void init(int array[], int n)
{
build_min(array, 1, 0, n - 1);
build_max(array, 1, 0, n - 1);
}
// Check if the given range is Consecutive
static boolean isConsecutive(int x, int y, int n)
{
return ((query_max(1, 0, n - 1, x, y) -
query_min(1, 0, n - 1, x, y)) == (y - x));
}
// Driver code
public static void main(String[] args)
{
int arr[] = { 2, 4, 3, 7, 6, 1 };
int query[][] = { { 1, 3 }, { 3, 5 }, { 5, 6 } };
int n = arr.length, q = 3;
init(arr, n);
for (int i = 0; i < q; i++)
{
int l, r;
l = query[i][0];
r = query[i][1];
System.out.print((isConsecutive(l - 1, r - 1, n) ?
"Yes" : "No") + "\n");
}
}
}
// This code is contributed by PrinciRaj1992
Python
# Python3 implementation of the above approach.
# Segment tree
tree_min = [0] * 1000001
tree_max = [0] * 1000001
# Segment tree for minimum element
def build_min(array, node,left, right):
# If left is equal to right
if (left == right):
tree_min[node] = array[left]
else :
# Divide the segment into equal halves
build_min(array, 2 * node, left,(left + right) // 2)
build_min(array, 2 * node + 1,(left + right) // 2 + 1, right)
# Update the element as minimum
# of the divided two subarrays
tree_min[node] = min(tree_min[2 * node], tree_min[2 * node + 1])
# Query to find a minimum
# in a given ranges
def query_min(node, c_l, c_r, l, r):
# Out of range
if (c_l > r or c_r < l):
return 10**9
# Within the range completely
if (c_l >= l and c_r <= r):
return tree_min[node]
else:
# Divide the range into two halves
# Query for each half
# and return the minimum of two
return min(query_min(2 * node, c_l,(c_l + c_r) // 2, l, r),
query_min(2 * node + 1, (c_l + c_r) // 2 + 1,c_r, l, r))
# Segment tree for maximum element
def build_max(array, node, left, right):
# If left is equal to right
if (left == right):
tree_max[node] = array[left]
else :
# Divide the segment into equal halves
build_max(array, 2 * node, left,(left + right) // 2)
build_max(array, 2 * node + 1,(left + right) // 2 + 1, right)
# Update the element as maximum
# of the divided two subarrays
tree_max[node] = max(tree_max[2 * node],tree_max[2 * node + 1])
# Query to find maximum
# in a given ranges
def query_max(node, c_l, c_r, l, r):
# Out of range
if (c_l > r or c_r < l):
return -1
# Within the range completely
if (c_l >= l and c_r <= r):
return tree_max[node]
else:
# Divide the range into two halves
# and query for each half
# and return the maximum of two
return max(query_max(2 * node, c_l,(c_l + c_r) // 2, l, r),query_max(2 * node + 1,(c_l + c_r) // 2 + 1,c_r, l, r))
# Build the tree
def init(array, n):
build_min(array, 1, 0, n - 1)
build_max(array, 1, 0, n - 1)
# Check if the given range is Consecutive
def isConsecutive(x, y, n):
return ((query_max(1, 0, n - 1, x, y) - query_min(1, 0, n - 1, x, y)) == (y - x))
# Driver code
arr = [2, 4, 3, 7, 6, 1]
query = [ [1, 3] , [3, 5 ], [5, 6] ]
n = len(arr)
q = 3
init(arr, n)
for i in range(q):
l = query[i][0]
r = query[i][1]
if (isConsecutive(l - 1, r - 1, n) ):
print("Yes")
else:
print("No")
# This code is contributed by mohit kumar 29
C#
// C# implementation of the above approach.
using System;
class GFG
{
// Segment tree
static int[] tree_min = new int[1000001];
static int[] tree_max = new int[1000001];
// Functions to return
// minimum and maximum
static int min(int a, int b)
{
return a < b ? a : b;
}
static int max(int a, int b)
{
return a > b ? a : b;
}
// Segment tree for minimum element
static void build_min(int []array, int node,
int left, int right)
{
// If left is equal to right
if (left == right)
tree_min[node] = array[left];
else
{
// Divide the segment into equal halves
build_min(array, 2 * node, left, (left + right) / 2);
build_min(array, 2 * node + 1,
(left + right) / 2 + 1, right);
// Update the element as minimum
// of the divided two subarrays
tree_min[node] = Math.Min(tree_min[2 * node],
tree_min[2 * node + 1]);
}
}
// Query to find a minimum
// in a given ranges
static int query_min(int node, int c_l,
int c_r, int l, int r)
{
// Out of range
if (c_l > r || c_r < l)
return (int) 1e9;
// Within the range completely
if (c_l >= l && c_r <= r)
return tree_min[node];
else
// Divide the range into two halves
// Query for each half
// and return the minimum of two
return min(query_min(2 * node, c_l,
(c_l + c_r) / 2, l, r),
query_min(2 * node + 1,
(c_l + c_r) / 2 + 1, c_r, l, r));
}
// Segment tree for maximum element
static void build_max(int []array, int node,
int left, int right)
{
// If left is equal to right
if (left == right)
tree_max[node] = array[left];
else
{
// Divide the segment into equal halves
build_max(array, 2 * node, left, (left + right) / 2);
build_max(array, 2 * node + 1, (left + right) / 2 + 1, right);
// Update the element as maximum
// of the divided two subarrays
tree_max[node] = Math.Max(tree_max[2 * node],
tree_max[2 * node + 1]);
}
}
// Query to find maximum
// in a given ranges
static int query_max(int node, int c_l,
int c_r, int l, int r)
{
// Out of range
if (c_l > r || c_r < l)
return -1;
// Within the range completely
if (c_l >= l && c_r <= r)
return tree_max[node];
else
// Divide the range into two halves
// and query for each half
// and return the maximum of two
return Math.Max(query_max(2 * node, c_l,
(c_l + c_r) / 2, l, r),
query_max(2 * node + 1,
(c_l + c_r) / 2 + 1, c_r, l, r));
}
// Build the tree
static void init(int []array, int n)
{
build_min(array, 1, 0, n - 1);
build_max(array, 1, 0, n - 1);
}
// Check if the given range is Consecutive
static bool isConsecutive(int x, int y, int n)
{
return ((query_max(1, 0, n - 1, x, y) -
query_min(1, 0, n - 1, x, y)) == (y - x));
}
// Driver code
public static void Main(String[] args)
{
int []arr = {2, 4, 3, 7, 6, 1};
int [,]query = {{ 1, 3 }, { 3, 5 }, { 5, 6 }};
int n = arr.Length, q = 3;
init(arr, n);
for (int i = 0; i < q; i++)
{
int l, r;
l = query[i,0];
r = query[i,1];
Console.Write((isConsecutive(l - 1, r - 1, n) ?
"Yes" : "No") + "\n");
}
}
}
// This code is contributed by Rajput-Ji
Javascript
输出:
Yes
No
No
时间复杂度: O(Q*log(n))