Find k most frequent in linear time

 

Find k most frequent in linear time

Given an array of integers, we need to print k most frequent elements. If there is a tie, we need to prefer the elements whose first appearance is first.

Examples:

Input : arr[] = {10, 5, 20, 5, 10, 10, 30}, k = 2
Output : 10 5

Input : arr[] = {7, 7, 6, 6, 6, 7, 5, 4, 4, 10, 5}, k = 3
Output : 7 6 5
Explanation :
In this example, 7 and 6 have same frequencies. We print 7 first because first appearance of 7 is first. Similarly, 5 and 4 have same frequencies. We prefer 5 because 5’s first appearance is first.

Let us first talk about a simple solution that prints in any order in case of tie. Then we will discuss the solution that takes of the order.

The idea is to use hashing with frequency indexing. We first store counts in a hash. Then we traverse through the hash and use frequencies as index to store elements with given frequencies. The important factor here is, maximum frequency can be n. So an array of size n+1 would be good.

// C++ implementation to find k numbers with most
// occurrences in the given array
#include <bits/stdc++.h>
using namespace std;
  
// funnction to print the k numbers with most occurrences
void print_N_mostFrequentNumber(int arr[], int n, int k)
{
    // unordered_map 'um' implemented as frequency
    // hash table
    unordered_map<int, int> um;
    for (int i = 0; i < n; i++)
        um[arr[i]]++;
  
    // Use frequencies as indexes and put
    // elements with given frequency in a
    // vector (related to a frequency)
    vector<int> freq[n + 1];
    for (auto x : um)
        freq[x.second].push_back(x.first);
  
    // Initialize count of items printed
    int count = 0;
  
    // Traverse the frequency array from
    // right side as we need the most
    // frequent items.
    for (int i = n; i >= 0; i--) {
  
        // Print items of current frequency
        for (int x : freq[i]) {
            cout << x << " ";
            count++;
            if (count == k)
                return;
        }
    }
}
  
// Driver program to test above
int main()
{
    int arr[] = { 3, 1, 4, 4, 5, 2, 6, 1 };
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = 2;
    print_N_mostFrequentNumber(arr, n, k);
    return 0;
}
Output:
4 1

Time Complexity : O(n)
Auxiliary Space : O(n)


Printing according to first appearance. To keep the required order, we traverse the original array instead of map. To avoid duplicates, we need to mark processed entries as -1 in map.


// C++ implementation to find k numbers with most
// occurrences in the given array
#include <bits/stdc++.h>
using namespace std;
  
// function to print the k numbers with most occurrences
void print_N_mostFrequentNumber(int arr[], int n, int k)
{
    // unordered_map 'um' implemented as frequency
    // hash table
    unordered_map<int, int> um;
    for (int i = 0; i < n; i++)
        um[arr[i]]++;
  
    // Use frequencies as indexes and put
    // elements with given frequency in a
    // vector (related to a frequency)
    vector<int> freq[n + 1];
    for (int i = 0; i < n; i++) {
        int f = um[arr[i]];
        if (f != -1) {
            freq[f].push_back(arr[i]);
            um[arr[i]] = -1;
        }
    }
  
    // Initialize count of items printed
    int count = 0;
  
    // Traverse the frequency array from
    // right side as we need the most
    // frequent items.
    for (int i = n; i >= 0; i--) {
  
        // Print items of current frequency
        for (int x : freq[i]) {
            cout << x << " ";
            count++;
            if (count == k)
                return;
        }
    }
}
  
// Driver program to test above
int main()
{
    int arr[] = { 3, 1, 4, 4, 5, 2, 6, 1 };
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = 3;
    print_N_mostFrequentNumber(arr, n, k);
    return 0;
}
Output:
1 4 3

Time Complexity : O(n)
Auxiliary Space : O(n)























































































Comments

Popular posts from this blog

Kth most frequent Character in a given String

[16 Feb 2020] Given an array where every element occurs three times, except one element which occurs only once.

[17 Feb 2020] Given an array of integers, find the nearest smaller number for every element such that the smaller element is on left side.