📌  相关文章
📜  查询以检查数组的[L,R]范围内是否存在任何非重复元素

📅  最后修改于: 2021-04-26 06:17:59             🧑  作者: Mango

给定一个由整数组成的数组arr [] ,查询形式为(L,R)的Q ,任务是检查索引[L,R] (基于1的索引)中是否存在任何非重复元素。如果至少有一个非重复元素,则打印“是” 。否则,打印“否”

例子:

天真的方法:
解决该问题的最简单方法是为每个查询迭代给定的子数组,并维护一个用于存储每个元素的频率的映射。遍历地图并检查是否存在频率为1的元素。

时间复杂度: O(Q * N)
辅助空间复杂度: O(N)

高效方法:该解决方案的主要观察结果是,对于给定数组中元素的频率为1,该数组在该数组中的上一次出现严格小于查询l,而下一次出现的元素严格大于r一些查询。使用此观察来查找订单。以下是使用“合并排序树”方法来解决给定问题的步骤:

  1. 将数组中每个ith元素的上次出现和下一次出现存储为对。
  2. 构建合并排序树,并根据先前的事件在其中合并节点。合并函数用于合并范围。
  3. 在合并排序树的每个节点上,在下一次出现时都保持最大前缀,因为我们需要某个元素的前一次出现尽可能地小,而下一次出现时则需要尽可能大。
  4. 为了回答查询,我们需要先前出现的节点严格小于l。
  5. 对于合并排序树中前一个出现次数小于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))