Нахождение частоты чисел в заданной группе чисел

Предположим, у нас есть вектор / массив на C++, и мы хотим подсчитать, какой из этих N элементов имеет максимальное количество повторяющихся вхождений, и вывести наибольшее количество. Какой алгоритм лучше всего подходит для этой работы.

пример:

int a = { 2, 456, 34, 3456, 2, 435, 2, 456, 2}

выход 4, потому что 2 встречается 4 раза. Это максимальное количество раз, которое встречается 2 раза.

Я использую карту STL для заполнения частот и сортировки с помощью sort (map.begin (), map.end ()), чтобы получить больше скорости?

Abhishek Mishra 28.09.2008 18:17

Если вопрос «какой номер», ответ должен быть 2, а не 4 ;-).

Toon Krijthe 28.09.2008 19:41

Это пахнет домашним заданием.

jfm3 28.09.2008 20:38

скорость - это не домашнее задание! это больше о конкуренции, если хорошенько подумать

Abhishek Mishra 28.09.2008 20:50

@Gamecat вопрос, к сожалению, какая частота максимальная

Abhishek Mishra 28.09.2008 20:50

На самом деле, это был первый вопрос в нескольких интервью.

Uri 28.09.2008 21:06

ой это ??? так они вообще недоуменно спрашивают в интервью? я понятия не имел о том, что происходит вокруг !!

Abhishek Mishra 28.09.2008 21:18

это должно быть "int a [] = ..."?

Alastair 17.11.2008 03:47
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
8
6 634
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Ответ принят как подходящий

Отсортируйте массив, а затем выполните быстрый проход для подсчета каждого числа. Алгоритм имеет сложность O (N * logN).

В качестве альтернативы создайте хеш-таблицу, используя номер в качестве ключа. Сохраните в хеш-таблице счетчик для каждого введенного вами элемента. Вы сможете подсчитать все элементы за один проход; однако сложность алгоритма теперь зависит от сложности вашей хэш-функции.

да, вот о чем я думал

Midhat 28.09.2008 13:56

Эээ, да. Здесь 3 часа ночи, а у меня трехнедельный ребенок, если это можно считать оправданием. :-)

Franci Penov 28.09.2008 14:03

Не нужно оправдываться - в конце концов, SO - это совместная работа :)

Torsten Marek 28.09.2008 14:04

Поскольку после сортировки вам не нужен внешний счетчик для каждого числа, вы можете сохранить только один счетчик для текущего числа и один для максимального числа.

Franci Penov 28.09.2008 14:29

Хорошо, я предполагаю, что массив достаточно мал, в конце концов, он находится в памяти для начала.

Sklivvz 28.09.2008 14:36

Единственное, что вы можете сделать, это то, что массив достаточно мал, чтобы уместиться в доступной памяти. Вам не обязательно иметь достаточно памяти, чтобы уместить еще один массив того же размера. Даже если у вас достаточно виртуальной памяти, вы все равно можете закончить подкачку и потерять прирост скорости от вашего алгоритма.

Franci Penov 28.09.2008 14:42

Не говоря уже о том, что у вас может даже не быть виртуальной памяти и чего-то порядка 64 КБ физической памяти. Да, некоторые люди до сих пор пишут код для таких устройств. По крайней мере, с этой частью жизни я покончил. :-)

Franci Penov 28.09.2008 14:46

Если массив достаточно велик, вы можете итеративно читать с диска, тогда как я не уверен, что вы можете сортировать с диска? (открытый вопрос)

Sklivvz 28.09.2008 14:49

Если массив достаточно большой, чтобы не умещаться в памяти, это совсем другая история. :-) Я не спорю с предположением, что он умещается в памяти. Однако вы не можете ничего предположить о доступной памяти после чтения массива. Вам может не хватить счетчиков на все элементы.

Franci Penov 28.09.2008 15:00

Почему набор хешей, а не набор деревьев? Это числа, которые с большей вероятностью получат O (logN) при поиске.

Uri 28.09.2008 21:06

Ну, потому что была поздняя ночь, и я не продумала свой ответ до конца. :-) Более серьезно - хеш-таблица может иметь сложность O (1) (и, конечно, с огромным объемом памяти) в зависимости от хеш-функции.

Franci Penov 29.09.2008 01:00

А хеш по определению не гарантирует уникальности, поэтому второй подход не сработает.

Matt Cruikshank 20.10.2008 07:48

Хеширование обычно считается O (1), предполагая, что слова / числа, которые нужно хешировать, не масштабируются с размером проблемы. Что касается столкновений; в хорошей хеш-функции они тоже будут амортизироваться до O (1) раз. У деревьев будет O (log (n)) r / w. Ответ хорош как есть.

ejgottl 20.10.2008 08:04

немного псевдокода:

//split string into array firts
strsplit(numbers) //PHP function name to split a string into it's components
i=0
while( i < count(array))
 {
   if (isset(list[array[i]]))
    {
      list[array[i]]['count'] = list + 1
    }
   else
    {
      list[i]['count'] = 1
      list[i]['number']
    }
   i=i+1
 }
usort(list) //usort is a php function that sorts an array by its value not its key, Im assuming that you have something in c++ that does this
print list[0]['number'] //Should contain the most used number

Оптимизирован под пространство:

Быстрая сортировка (например) затем перебирает элементы, отслеживая только наибольшее количество. В лучшем случае O (N log N).

Оптимизирован по скорости:

Обходите все элементы, отслеживая отдельные подсчеты. Этот алгоритм всегда будет O (n).

При сортировке вам нужно сохранить длину самой длинной последовательности из одного числа. Если вы не сортируете, вам нужно хранить счетчики всех чисел в ассоциативном контейнере.

Torsten Marek 28.09.2008 14:19

Если вы отслеживаете количество каждого элемента, в худшем случае потребуется N счетчиков. Вы почти вдвое увеличили объем необходимой памяти. Конечно, для машины с памятью 4 ГБ это не будет большой проблемой. Однако для 64-килобайтной памяти, совместно используемой с ОС, вы, возможно, захотите отсортировать.

Franci Penov 28.09.2008 14:35

@Franci Penov: все дело в том, что в вопросе написано «лучше всего», а ответ зависит от чувства «лучше всего».

Sklivvz 28.09.2008 14:51

Ага, согласен. Поэтому я предложил два альтернативных решения - сортировку или хеш-таблицу счетчиков. :-) Сразу хотел указать на недостаток потребления памяти у второго алгоритма. Память тоже важна, а не только скорость.

Franci Penov 28.09.2008 15:03

Разве не самая большая проблема с версией "оптимизированной для скорости" состоит в том, что вам нужен массив размером, равным максимально возможному числу, чтобы сохранить O (n)? В противном случае вам нужно дерево для O (n * log n) или хеш для O (кто знает)?

markets 28.09.2008 17:38

Если у вас есть ОЗУ и ваши значения не слишком велики, используйте счетная сортировка.

Возможная реализация C++, использующая STL, может быть следующей:

#include <iostream>
#include <algorithm>
#include <map>

// functor
struct maxoccur
{
    int _M_val;
    int _M_rep;

    maxoccur()
    : _M_val(0),
      _M_rep(0)
    {}

    void operator()(const std::pair<int,int> &e)
    {
        std::cout << "pair: " << e.first << " " << e.second << std::endl;
        if ( _M_rep < e.second ) {
            _M_val = e.first;
            _M_rep = e.second;
        }
    }
};

int
main(int argc, char *argv[])
{
    int a[] = {2,456,34,3456,2,435,2,456,2};
    std::map<int,int> m; 

    // load the map
    for(unsigned int i=0; i< sizeof(a)/sizeof(a[0]); i++) 
        m [a[i]]++;

    // find the max occurence...
    maxoccur ret = std::for_each(m.begin(), m.end(), maxoccur());
    std::cout << "value:" << ret._M_val << " max repetition:" << ret._M_rep <<  std::endl;

    return 0;
}

Если диапазон элементов велик по сравнению с количеством элементов, я бы, как говорили другие, просто сортировал и просматривал. Это время n * log n и без дополнительного места (возможно, log n дополнительно).

Проблема со счетной сортировкой заключается в том, что, если диапазон значений велик, для инициализации счетного массива может потребоваться больше времени, чем для сортировки.

Алгоритм хеширования (build count [i] = #occurrences (i) в основном за линейное время) очень практичен, но теоретически не является строго O (n), потому что во время процесса могут возникать конфликты хешей.

Интересным частным случаем этого вопроса является алгоритм большинства, в котором вы хотите найти элемент, который присутствует как минимум в n / 2 записей массива, если такой элемент существует.

Вот быстрое объяснение и более подробное объяснение того, как это сделать в линейное время, без каких-либо ухищрений.

Вот моя полная, протестированная версия с использованием std::tr1::unordered_map.

Я делаю это примерно за O (n). Сначала он выполняет итерацию по n входным значениям для вставки / обновления счетчиков в unordered_map, затем выполняет partial_sort_copy, который равен O (n). 2 * O (n) ~ = O (n).

#include <unordered_map>
#include <vector>
#include <algorithm>
#include <iostream>

namespace {
// Only used in most_frequent but can't be a local class because of the member template
struct second_greater {
    // Need to compare two (slightly) different types of pairs
    template <typename PairA, typename PairB>
    bool operator() (const PairA& a, const PairB& b) const
        { return a.second > b.second; }
};
}

template <typename Iter>
std::pair<typename std::iterator_traits<Iter>::value_type, unsigned int>
most_frequent(Iter begin, Iter end)
{
    typedef typename std::iterator_traits<Iter>::value_type value_type;
    typedef std::pair<value_type, unsigned int> result_type;

    std::tr1::unordered_map<value_type, unsigned int> counts;

    for(; begin != end; ++begin)
        // This is safe because new entries in the map are defined to be initialized to 0 for
        // built-in numeric types - no need to initialize them first
        ++ counts[*begin];

    // Only need the top one at this point (could easily expand to top-n)
    std::vector<result_type> top(1);

    std::partial_sort_copy(counts.begin(), counts.end(),
                           top.begin(), top.end(), second_greater());

    return top.front();
}

int main(int argc, char* argv[])
{
    int a[] = { 2, 456, 34, 3456, 2, 435, 2, 456, 2 };

    std::pair<int, unsigned int> m = most_frequent(a, a + (sizeof(a) / sizeof(a[0])));

    std::cout << "most common = " << m.first << " (" << m.second << " instances)" << std::endl;
    assert(m.first == 2);
    assert(m.second == 4);

    return 0;
}

Это будет в O (n) ............ но дело в том, что нет. of array может принимать другой массив того же размера ............

для (i = 0; i

мар = счет [о]; index = o;

для (i = 0; i

тогда вывод будет ......... элемент показатель происходит для Максимум no. раз в этом массиве ........

здесь [] - это массив данных, в котором нам нужно найти максимальное количество определенных номеров. в массиве .......

count [], имеющий количество каждого элемента .......... Примечание: мы уже знаем, что диапазон данных будет в массиве .. скажем, например. данные в этом массиве варьируются от 1 до 100 ....... затем имейте массив счетчиков из 100 элементов для отслеживания, если произошло увеличение индексированного значения на единицу ........

Другие вопросы по теме