给定一个由整数和形式为(L, R) 的查询Q组成的数组arr[] ,任务是检查索引[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一些查询。使用此观察来查找顺序。以下是使用合并排序树方法解决给定问题的步骤:
- 将数组中每个第 i 个元素的上一次出现和下一次出现作为对存储。
- 构建合并排序树,并根据前一次出现合并其中的节点。合并函数用于合并范围。
- 在合并排序树的每个节点,在下一次出现时保持前缀最大值,因为我们需要尽可能少的前一次出现和尽可能大的下一次出现某个元素。
- 为了回答查询,我们需要先前出现的节点严格小于 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))
如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live