Find the Next Greater Frequency Element

In this tutorial, we will learn to write the Python program to find the next greater frequency element. We will solve this problem using the various approaches. Let's understand the problem statement.

We are given an array, and required to determine the nearest right element with a higher frequency. If there is no such element, assign it as -1. Let's understand the following example.

Example -

Input: a = [5, 3, 7, 2, 3, 8, 1]

Output: [-1, 7, -1, -1, 2, -1, -1]

Explanation:

Given array a = [5, 3, 7, 2, 3, 8, 1]

The frequency of each element is: [1, 2, 1, 2, 2, 1, 1]

The output represents the nearest right elements with higher frequencies.

Let's determine the Next Greater Frequency (NGF) element for each element in the array a[].

  1. For element a[0] = 1, which has a frequency of 3, there are no other elements to its right with a higher frequency, so the NGF element is '-1'.
  2. For element a[1] = 1 (with a frequency of 3), it also has no other elements to its right with a higher frequency, so it's NGF is '-1', similar to a[0].
  3. For element a[2] = 2 (with a frequency of 2), the NGF element is 1, which is located at position 6 and has a frequency of 3, which is greater than 2.
  4. For element a[3] = 3 (with a frequency of 1), the NGF element is 2, located at position 5, with a frequency of 2, which is greater than 1.
  5. For element a[4] = 4 (with a frequency of 1), the NGF element is 2, found at position 5, with a frequency of 2, which is greater than 1.
  6. For element a[5] = 2 (with a frequency of 2), the NGF element is 1, located at position 6, with a frequency of 3, which is greater than 2.
  7. For element a[6] = 1, there are no elements to its right, so it's NGF is '-1'.

In this way, we determine the NGF elements for each element in the array based on their frequencies and positions.

Let's solve this problem using the Naïve approach.

Solution -1: Naïve Approach

A hashing technique is a straightforward approach, where we use values as indices in a list to store the frequency of each element. This method requires only a single pass through the array. Then, we employ two loops:

  1. The outer loop selects each element one by one.
  2. The inner loop searches for the first element whose frequency is higher than the frequency of the current element where we use values as indices in a list to store the frequency of each element. This method requires only a single pass through the array. Then, we employ two loops:
  • The outer loop selects each element one by one.
  • The inner loop searches for the first element whose frequency is higher than the frequency of the current element.

Let's understand the following code snippet.

Example -

Output

[-1, -1, 1, 2, 2, 1, -1]

Explanation -

Let's understand the step-by-step explanation of the above code.

  1. First, we define the nextGreaterFrequencyElement() function. It counts the frequency of each element in the input array and stores this frequency information in a separate list called frequency.
  2. The outer loop iterates through each element of the input array using the variable i.
  3. For each element arr[i], it starts an inner loop that iterates from i+1 to the end of the array using the variable j.
  4. Inside the inner loop, it checks if the frequency of the current element arr[i] is less than the frequency of the element at position j. If it's true, then arr[j] is the NGF for arr[i], so it stores arr[j] in the result list. If not, it continues searching for the NGF in the inner loop.
  5. If the inner loop completes without finding an NGF with a higher frequency, it assigns -1 as the NGF for the current element arr[i].
  6. The NGF or -1 value is appended to the result list for each element.
  7. After processing all elements in the outer loop, the result list contains the NGF (or -1) for each element.
  8. The result list is then returned as the final output.

The code efficiently computes the NGF for each element by using frequency information and nested loops. It provides the NGF or -1 for each element, as described in the output and explanations.

Solution - 2: Using Stack (Efficient Approach)

In this approach, we will use the stack data structure to solve this problem effectively. Let's understand the following steps -

  1. First, we initialize an empty stack and a dictionary to store the frequency of each element in the array.
  2. Then, we initialize an empty result list to store the NGF elements.
  3. We iterate through the input array in reverse order. This reverse iteration is important because we want to find the next greater frequency elements to the right.
  4. for each element in the reverse order:
    • Check the frequency of the element from the dictionary.
    • While the stack is not empty and the frequency of the current element is greater than or equal to the frequency of the element at the top of the stack, pop elements from the stack and mark the NGF as the current element.
    • Push the current element onto the stack.
  5. If there are elements left in the stack after the loop, it means there are no greater frequency elements to the right for those elements. In this case, assign -1 as the NGF for those elements.
  6. The result list now contains the NGF elements for each element in the array, and it is in the correct order.

By using a stack to efficiently track the next greater frequency elements, this approach can find the NGF values with a time complexity of O(n), where n is the number of elements in the input array. It's more efficient than the brute-force approach, which involves nested loops.

Let's understand the following code snippet.

Example -

Output

NGF elements for each element: [-1, -1, -1, -1, -1]

Solution - 3 Brute Force Approach

The approach is straightforward: first, we store the frequency of all elements in a map. Then, we push all elements in reverse order onto a stack. Since the stack follows the Last-In-First-Out (LIFO) nature, we traverse the vector to find the Next Greater Frequency (NGF) for every element in the vector using both the stack and the map. This efficient technique allows us to determine the NGF for each element in the array.

Let's understand the following example -

Example -

Output

1 --> -1
1 --> -1
2 --> 1
3 --> 2
4 --> 2
2 --> 1
1 --> -1

Explanation -

Let's understand the flow of the above code -

  1. First, we import the defaultdict class from the collections module. This class is used to create a dictionary with default values.
  2. Then we define a function find_next_greater_frequency_element(arr) that takes a list arr as an input.
  3. We initialize a dictionary mp using defaultdict(int). This dictionary will store the frequency of each element in the input array.
  4. Then we create an empty list s. This list will be used as a stack to store elements in reverse order.
  5. Iterate through the input array arr and update the mp dictionary to count the frequency of each element.
  6. Create a stack s by iterating through the input array in reverse order and appending elements to it. This reverses the order of elements.
  7. Now, iterate through the original input array in its original order.
  8. For each element arr[i], retrieve its frequency from the mp dictionary and store it in the variable x.
  9. Initialize a flag to True. This flag will be used to determine if there is a Next Greater Frequency (NGF) element.
  10. Create a copy of the stack s and store it in the variable ss and use a while loop to iterate through the elements in ss.
  11. Check if the frequency of the last element in ss (denoted by ss[-1]) is greater than the frequency x. If it is, print the current element arr[i] and the NGF element ss[-1], set flag to False, and break out of the loop.
  12. If no NGF element is found, print the current element arr[i] and -1 to indicate that there is no NGF element with a greater frequency.
  13. Remove the last element from the stack s

Solution - 5 Space Approach

We can solve this problem more efficiently using the space efficient approach.

Let's understand the following steps.

  1. Create a class called "Pair" to store pairs of integers (element, frequency).
  2. Use a dictionary (HashMap) with pairs as keys and their frequencies as values to efficiently store the frequency of each element.
  3. Iterate through the input array, and for each element, store its frequency in the dictionary.
  4. Create an array called "res" to store the final output.
  5. Initialize the last element of the "res" array to -1 because the last element in the input array has no elements to the right, so it doesn't have a higher frequency element.
  6. Initialize an empty stack, which will be used to keep track of elements and their frequencies.
  7. Traverse the input array in reverse order, starting from the last element.
  8. For each element encountered in the array:
    1. Compare the frequency of the current element with the frequency of the element at the top of the stack.
    2. If the frequency of the current element is higher, pop elements from the stack and update their NGF values in the "res" array accordingly.
    3. Continue this process until the frequency condition is no longer met or until the stack is empty.
  9. If the stack becomes empty after popping elements, it means that there is no element with a higher frequency to the right of the current element. In this case, set -1 as the next higher frequency element in the "res" array for the current element.
  10. If the stack is not empty after processing, it means that the top element of the stack has a higher frequency than the current element. Set the top element's value as the next higher frequency element in the "res" array for the current element.
  11. Push the current element along with its frequency onto the stack.

These steps efficiently find and store the Next Greater Frequency (NGF) elements for each element in the input array, providing a clear and simplified approach to solving the problem.

Let's understand the following code snippet -

Example -

Output

[2, 2, 2, -1, -1, -1, -1, 3, -1, -1]

Conclusion

In this tutorial, we explored methods to find the Next Greater Frequency (NGF) element in an array. We covered a naive approach, an efficient stack-based solution, and a space-efficient approach, providing options for varying performance and memory requirements.