查找每个数组元素的频率

Find frequency of each array element

本文关键字:频率 数组元素 查找      更新时间:2023-10-16

我有这个黑客级的事情要做。 N 必须<= 1 000 000。每个元素必须在 20 到 50 之间,但我不知道如何做到这一点,没有做过太多的竞争性编程。 用户输入 N 个数字。该程序查找每个元素的频率并降序打印它们。 我尝试做一个while循环(见main),但这不起作用。请帮忙。

输入格式:

9

42 42 3426 42 35 34 47 47

输出:

42 3

34 2

47 2

26 1

35 1

#include <iostream>
#include <algorithm>
using namespace std;
struct ele
{
int count, index, val;
};

bool mycomp(struct ele a, struct ele b) {
return (a.val < b.val);
}
bool mycomp2(struct ele a, struct ele b) {
if (a.count != b.count) return (a.count < b.count);
else return a.index > b.index;
}
void sortByFrequency(int arr[], int n)
{
struct ele element[n];
for (int i = 0; i < n; i++)
{
element[i].index = i;
element[i].count = 0;
element[i].val = arr[i];
}
stable_sort(element, element + n, mycomp);
element[0].count = 1;
for (int i = 1; i < n; i++)
{
if (element[i].val == element[i - 1].val)
{
element[i].count += element[i - 1].count + 1;
element[i - 1].count = -1;
element[i].index = element[i - 1].index;
}
else element[i].count = 1;
}
stable_sort(element, element + n, mycomp2);
for (int i = n - 1, index = 0; i >= 0; i--)
if (element[i].count != -1)
for (int j = 0; j < element[i].count; j++)
arr[index++] = element[i].val;
}
int main() {
int n; cin >> n;
int* arr = new int[n];
int* seen = new int[n];
for (int i = 0; i < n; i++){
while(arr[i] < 20 || arr[i] > 50) 
cin >> arr[i];
}
sortByFrequency(arr, n);
for (int i = 0; i < n; i++) {
if (seen[i] == 0) {
int count = 0;
for (int j = i; j < n; j++)
if (arr[j] == arr[i]) {
count += 1;
seen[j] = 1;
}
cout << arr[i] << " " << count << endl;
}
}
}

并不是说我认为竞争性编程有助于提高编程技能。(至少,不是日常业务的编程技能。然而,我被诱惑了,无法抗拒。(今天是周一早上,可能是一周的一个很好的热身。

编译评论的想法,我得到了这个:

#include <cassert>
#include <iostream>
#include <vector>
#include <set>
int main()
{
// input and count frequency
int n; std::cin >> n;
assert(n >= 0 && n < 1000000);
const int valueMin = 20, valueMax = 50;
int freq[valueMax - valueMin + 1] {};
for (int i = 0; i < n; ++i) {
int value; std::cin >> value;
++freq[value - valueMin];
}
// sort frequency
std::set<std::pair<int, int>, bool(*)(const std::pair<int, int>&, const std::pair<int, int>&)>
freqSorted([](const std::pair<int, int> &pair1, const std::pair<int, int> &pair2) {
if (pair1.first != pair2.first) return pair1.first > pair2.first;
return pair1.second < pair2.second;
});
for (int i = valueMin; i <= valueMax; ++i) {
if (const int freqI = freq[i - valueMin]) {
freqSorted.insert(std::make_pair(freqI, i));
}
}
// output
for (std::pair<int, int> entry : freqSorted) {
std::cout << entry.second << ' ' << entry.first << 'n';
}
}

笔记:

  1. 我使用

    const int valueMin = 20, valueMax = 50;
    int freq[valueMax - valueMin + 1] {};
    

    以最小的内存占用量存储出现次数。(对输入值范围的明确限制鼓励了我。

  2. user4581301 让我对内存消耗很敏感。(在阅读它之前,我没有意识到实际上没有必要存储输入值。

  3. 使用std::map(如毗湿奴达苏推荐的)也是我的第一个想法。在测试时,我想知道缺少结果,直到我意识到以出现次数为键的map将仅存储具有相同频率的多个值之一。 因此,我将其更改为两个值作为键的std::set

输出:

42 3
34 2
47 2
26 1
35 1

科里鲁的现场演示

有时我想知道,可以为简单的任务编写多少行代码。无论如何。

有一种或多或少的标准方法可以对一般或容器中的某物进行计数。

我们可以使用关联容器,例如std::mapstd::unordered_map.在这里,我们将一个"键"(在本例中为数字)与计数(在本例中为特定数字的计数)相关联。

幸运的是,地图有一个非常好的索引运算符[]。这将查找给定的键,如果找到,则返回对该值的引用。如果未找到,则它将使用键创建一个新条目,并返回对新条目的引用。因此,在这两种情况下,我们都将获得对用于计数的值的引用。然后我们可以简单地写:

std::unordered_map<int,unsigned int> counter{};
counter[value]++;

这看起来非常直观。

完成此操作后,您已经拥有频率表。要么按键(值)排序,要么使用std::map排序,要么未排序,但可通过std::unordered_map更快地访问。由于std::unordered_map使用哈希,因此通常非常快。

现在您要根据频率/计数进行排序。不幸的是,这在地图上是不可能的。

因此,我们需要使用第二个容器,例如std::vector,然后我们可以对任何给定谓词的取消std::sort进行排序,或者,我们可以将值复制到容器中,例如隐式排序其元素的std::multiset

这就是我们将要做什么以及将产生一些非常紧凑的代码:

#include <iostream>
#include <utility>
#include <unordered_map>
#include <type_traits>
#include <set>
// ------------------------------------------------------------
// Create aliases. Save typing work and make code more readable
using Pair = std::pair<int, unsigned int>;
// Standard approach for counter
using Counter = std::unordered_map<Pair::first_type, Pair::second_type>;
// Sorted values will be stored in a multiset
struct Comp { bool operator ()(const Pair& p1, const Pair& p2) const { return (p1.second == p2.second) ? p1.first<p2.first : p1.second>p2.second; } };
using Sorter = std::multiset<Pair, Comp>;
// ------------------------------------------------------------
int main() {
// Read number of elements to check
if (int numberOfElements{}; std::cin >> numberOfElements) {
// Read and count
Counter counter{};
for (int i{}, value{}; (i < numberOfElements) && (std::cin >> value); counter[value]++, ++i);
// Sort
Sorter sorter(counter.begin(), counter.end());
// Show result
for (const auto& [value, count] : sorter) std::cout << value << ' ' << count << 'n';
}
}