📌  相关文章
📜  在 C++ STL 中使用 Set 计算右侧较小的元素

📅  最后修改于: 2022-05-13 01:57:51.539000             🧑  作者: Mango

在 C++ STL 中使用 Set 计算右侧较小的元素

编写一个函数来计算数组中每个元素右侧的较小元素的数量。给定一个由不同整数组成的未排序数组 arr[],构造另一个数组 countSmaller[],使得 countSmaller[i] 包含数组中每个元素 arr[i] 右侧的较小元素的计数。
例子:

Input : arr[] =  {12, 1, 2, 3, 0, 11, 4}
Output :countSmaller[]  =  {6, 1, 1, 1, 0, 1, 0} 

Input :arr[]={5, 4, 3, 2, 1}
Output :countSmaller[]={4, 3, 2, 1, 0}

在这篇文章中,讨论了 https://www.geeksforgeeks.org/count-smaller-elements-on-right-side/ 的简单实现。
在 C++ STL 中创建一个空集(注意 C++ STL 中的集是实现自平衡二叉搜索树)。

  1. 遍历数组元素从 i=len-1 到 0 并插入集合中的每个元素。
  2. 使用 lower_bound函数查找低于 A[i] 的第一个元素。
  3. 使用距离函数查找上面找到的元素与集合开始之间的距离。
  4. 将距离存储在另一个数组中让我们说 CountSmaller。
  5. 打印该数组。
CPP
// CPP program to find count of smaller
// elements on right side using set in C++
// STL.
#include 
using namespace std;
void countSmallerRight(int A[], int len)
{
    set s;
    int countSmaller[len];
    for (int i = len - 1; i >= 0; i--) {
        s.insert(A[i]);
        auto it = s.lower_bound(A[i]);
        countSmaller[i] = distance(s.begin(), it);
    }
 
    for (int i = 0; i < len; i++)
        cout << countSmaller[i] << " ";
}
 
// Driver code
int main()
{
    int A[] = {12, 1, 2, 3, 0, 11, 4};
    int len = sizeof(A) / sizeof(int);
    countSmallerRight(A, len);
    return 0;
}


C++
// C++ implementation of the above approach
#include 
#include 
#include 
#define pbds                                               \
    tree, null_type, less >, \
         rb_tree_tag, tree_order_statistics_node_update>
using namespace __gnu_pbds;
using namespace std;
 
// Function to find number of smaller elements
// to the right of every element
void countSmallerRight(int arr[], int n)
{
    pbds s;
    // stores the answer
    vector ans;
    for (int i = n - 1; i >= 0; i--) {
        if (i == n - 1) { // for the last element answer is
                          // zero
            ans.push_back(0);
        }
        else { // insert number of the smaller elements
            // to the right of current element into the ans
            ans.push_back(s.order_of_key({ arr[i], i }));
        }
        // insert current element
        s.insert({ arr[i], i });
    }
 
    reverse(ans.begin(), ans.end());
    for (auto x : ans)
        cout << x << " ";
}
 
// Driver Code
int main()
{
    int n = 7;
    int arr[] = { 12, 1, 2, 3, 0, 11, 4 };
    countSmallerRight(arr, n);
    return 0;
}


输出
6 1 1 1 0 1 0 

请注意,上述实现采用最坏情况时间复杂度 O(n^2),因为距离函数的最坏情况时间复杂度为 O(n),但上述实现非常简单,并且在平均情况下比朴素算法工作得更好。
上述方法适用于唯一元素,但对于重复元素只需将 Set 替换为 Multiset。

高效方法:在 C++ STL 中使用基于策略的数据结构。

维护基于策略的数据对数据结构,以解决重复问题。

  • 我们将从数组末尾开始遍历数组,每次找到当前元素的 order_of_key 以查找其右侧较小元素的数量。
  • 然后我们将当前元素插入到基于策略的数据结构中。

下面是上述方法的实现:

C++

// C++ implementation of the above approach
#include 
#include 
#include 
#define pbds                                               \
    tree, null_type, less >, \
         rb_tree_tag, tree_order_statistics_node_update>
using namespace __gnu_pbds;
using namespace std;
 
// Function to find number of smaller elements
// to the right of every element
void countSmallerRight(int arr[], int n)
{
    pbds s;
    // stores the answer
    vector ans;
    for (int i = n - 1; i >= 0; i--) {
        if (i == n - 1) { // for the last element answer is
                          // zero
            ans.push_back(0);
        }
        else { // insert number of the smaller elements
            // to the right of current element into the ans
            ans.push_back(s.order_of_key({ arr[i], i }));
        }
        // insert current element
        s.insert({ arr[i], i });
    }
 
    reverse(ans.begin(), ans.end());
    for (auto x : ans)
        cout << x << " ";
}
 
// Driver Code
int main()
{
    int n = 7;
    int arr[] = { 12, 1, 2, 3, 0, 11, 4 };
    countSmallerRight(arr, n);
    return 0;
}
输出
6 1 1 1 0 1 0 

时间复杂度: O(N*LogN)