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

📅  最后修改于: 2021-09-16 11:17:55             🧑  作者: Mango

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

例子:

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

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

有效的方法:解决方案的关键观察是,对于给定数组中频率为 1 的元素,该数字在数组中的前一次出现严格小于查询 l 并且该元素的下一次出现严格大于 r一些查询。使用此观察来查找顺序。以下是使用合并排序树方法解决给定问题的步骤:

  1. 将数组中每个第 i 个元素的上一次出现和下一次出现作为对存储。
  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))

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程