给定一个由整数组成的数组arr [] ,查询形式为(L,R)的Q ,任务是检查索引[L,R] (基于1的索引)中是否存在任何非重复元素。如果至少有一个非重复元素,则打印“是” 。否则,打印“否” 。
例子:
Input: arr[] = {1, 2, 1, 2, 3, 4}, Queries[][] = {{1, 4}, {1, 5}}
Output: No Yes
Explanation:
For the first query, the subarray is {1, 2, 1, 2}, we can see that both number have frequency 2. Therefore, the answer is No.
For the second query, the subarray is {1, 2, 1, 2, 3}, we can see that 3 has frequency 1 so the answer is Yes.
Input: arr[] = {1, 2, 3, 4, 5}, Queries[][] = {{1, 4}}
Output: Yes
Explanation: The subarray is {1, 2, 3, 4}, has all elements as frequency 1 so the answer is Yes.
天真的方法:
解决该问题的最简单方法是为每个查询迭代给定的子数组,并维护一个用于存储每个元素的频率的映射。遍历地图并检查是否存在频率为1的元素。
时间复杂度: O(Q * N)
辅助空间复杂度: O(N)
高效方法:该解决方案的主要观察结果是,对于给定数组中元素的频率为1,该数组在该数组中的上一次出现严格小于查询l,而下一次出现的元素严格大于r一些查询。使用此观察来查找订单。以下是使用“合并排序树”方法来解决给定问题的步骤:
- 将数组中每个ith元素的上次出现和下一次出现存储为对。
- 构建合并排序树,并根据先前的事件在其中合并节点。合并函数用于合并范围。
- 在合并排序树的每个节点上,在下一次出现时都保持最大前缀,因为我们需要某个元素的前一次出现尽可能地小,而下一次出现时则需要尽可能大。
- 为了回答查询,我们需要先前出现的节点严格小于l。
- 对于合并排序树中前一个出现次数小于l的元素,找到最大下一个出现次数,并检查下一个出现次数是否大于查询的r,则子数组中存在一个频率为1的元素。
下面是上述方法的实现:
CPP
// C++ program for the above approach
#include
using namespace std;
const int INF = 1e9 + 9;
const int N = 1e5 + 5;
// Merge sort of pair type for storing
// prev and next occurrences of element
vector > > segtree(4 * N);
// Stores the occurrences
vector > occurrences(N);
// Finds occurrences
vector > pos(N);
int n;
// Function to build merge sort tree
void build(int node = 0, int l = 0,
int r = n - 1)
{
// For leaf node, push the prev &
// next occurrence of the lth node
if (l == r) {
segtree[node].push_back(occurrences[l]);
return;
}
int mid = (l + r) / 2;
// Left recursion call
build(2 * node + 1, l, mid);
// Right recursion call
build(2 * node + 2, mid + 1, r);
// Merging the left child and right child
// according to the prev occurrence
merge(segtree[2 * node + 1].begin(),
segtree[2 * node + 1].end(),
segtree[2 * node + 2].begin(),
segtree[2 * node + 2].end(),
back_inserter(segtree[node]));
// Update the next occurrence
// with prefix maximum
int mx = 0;
for (auto& i : segtree[node]) {
// Update the maximum
// next occurrence
mx = max(mx, i.second);
// Update the next occurrence
// with prefix max
i.second = mx;
}
}
// Function to check whether an
// element is present from x to y
// with frequency 1
bool query(int x, int y, int node = 0,
int l = 0, int r = n - 1)
{
// No overlap condition
if (l > y || r < x || x > y)
return false;
// Complete overlap condition
if (x <= l && r <= y) {
// Find the first node with
// prev occurrence >= x
auto it = lower_bound(segtree[node].begin(),
segtree[node].end(),
make_pair(x, -1));
// No element in this range with
// previous occurrence less than x
if (it == segtree[node].begin())
return false;
else {
it--;
// Check if the max next
// occurrence is greater
// than y or not
if (it->second > y)
return true;
else
return false;
}
}
int mid = (l + r) / 2;
bool a = query(x, y, 2 * node + 1, l, mid);
bool b = query(x, y, 2 * node + 2, mid + 1, r);
// Return if any of the
// children returned true
return (a | b);
}
// Function do preprocessing that
// is finding the next and previous
// occurrences
void preprocess(int arr[])
{
// Store the position of
// every element
for (int i = 0; i < n; i++) {
pos[arr[i]].insert(i);
}
for (int i = 0; i < n; i++) {
// Find the previous
// and next occurrences
auto it = pos[arr[i]].find(i);
if (it == pos[arr[i]].begin())
occurrences[i].first = -INF;
else
occurrences[i].first = *prev(it);
// Check if there is no next occurrence
if (next(it) == pos[arr[i]].end())
occurrences[i].second = INF;
else
occurrences[i].second = *next(it);
}
// Building the merge sort tree
build();
}
// Function to find whether there is a
// number in the subarray with 1 frequency
void answerQueries(int arr[],
vector >& queries)
{
preprocess(arr);
// Answering the queries
for (int i = 0; i < queries.size(); i++) {
int l = queries[i].first - 1;
int r = queries[i].second - 1;
bool there = query(l, r);
if (there == true)
cout << "Yes\n";
else
cout << "No\n";
}
}
// Driver Code
int main()
{
int arr[] = { 1, 2, 1, 2, 3, 4 };
n = sizeof(arr) / sizeof(arr[0]);
vector > queries = { { 1, 4 }, { 1, 5 } };
answerQueries(arr, queries);
}
No
Yes
时间复杂度: O(N * log(N)+ Q * log 2 (N))
辅助空间: O(N * log(N))