在 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 中的集是实现自平衡二叉搜索树)。
- 遍历数组元素从 i=len-1 到 0 并插入集合中的每个元素。
- 使用 lower_bound函数查找低于 A[i] 的第一个元素。
- 使用距离函数查找上面找到的元素与集合开始之间的距离。
- 将距离存储在另一个数组中让我们说 CountSmaller。
- 打印该数组。
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)