{x}
blog image

Frequency of the Most Frequent Element

The frequency of an element is the number of times it occurs in an array.

You are given an integer array nums and an integer k. In one operation, you can choose an index of nums and increment the element at that index by 1.

Return the maximum possible frequency of an element after performing at most k operations.

 

Example 1:

Input: nums = [1,2,4], k = 5
Output: 3
Explanation: Increment the first element three times and the second element two times to make nums = [4,4,4].
4 has a frequency of 3.

Example 2:

Input: nums = [1,4,8,13], k = 5
Output: 2
Explanation: There are multiple optimal solutions:
- Increment the first element three times to make nums = [4,4,8,13]. 4 has a frequency of 2.
- Increment the second element four times to make nums = [1,8,8,13]. 8 has a frequency of 2.
- Increment the third element five times to make nums = [1,4,13,13]. 13 has a frequency of 2.

Example 3:

Input: nums = [3,9,6], k = 2
Output: 1

 

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 105
  • 1 <= k <= 105

Solution Explanation for Frequency of the Most Frequent Element

This problem asks to find the maximum possible frequency of an element in an array after performing at most k operations, where each operation increments an element by 1. Two efficient approaches are presented: sorting with binary search and sorting with two pointers.

This approach leverages the fact that the element with the highest frequency after operations will always be one of the original elements in the array.

  1. Sorting: The input array nums is sorted in ascending order. This allows for efficient windowing and prefix sum calculations.

  2. Prefix Sum: A prefix sum array s is computed. s[i] represents the sum of elements from nums[0] to nums[i-1]. This enables quick calculation of the sum of elements within a subarray.

  3. Binary Search: A binary search is performed to find the maximum frequency m. The check function verifies if a frequency m is achievable within the constraint of k operations. For a given m, the check function iterates through possible subarrays of length m. For each subarray, it calculates the operations needed to make all elements equal to the maximum element in that subarray. If this number of operations is less than or equal to k, the frequency m is achievable.

  4. Return Value: The binary search returns the maximum frequency m that satisfies the condition.

Time Complexity: O(n log n) due to sorting and O(n log n) due to the binary search (in the worst case the check function is called O(n) times within the binary search loop). Space Complexity: O(n) for the prefix sum array s.

Approach 2: Sorting + Two Pointers (Sliding Window)

This approach uses a sliding window technique with two pointers for efficiency.

  1. Sorting: The array nums is sorted.

  2. Sliding Window: Two pointers, j (left) and i (right), define a window. Initially, both point to the beginning of the array.

  3. Window Operations: The code iteratively expands the window to the right. For each expansion, it calculates the total operations s needed to increase all elements within the window to nums[i] (the largest element in the window).

  4. Window Adjustment: If s exceeds k, the left pointer j is moved to the right, shrinking the window until s is less than or equal to k. This maintains the condition that the operations stay within the limit.

  5. Max Frequency: The maximum window size (i - j + 1) encountered during the iteration represents the maximum frequency.

Time Complexity: O(n log n) due to sorting and O(n) due to the two-pointer iteration. Space Complexity: O(log n) - space used by sorting algorithms (in-place sorting might reduce to O(1)).

Code Examples (Python)

Approach 1:

from itertools import accumulate
 
class Solution:
    def maxFrequency(self, nums: List[int], k: int) -> int:
        n = len(nums)
        nums.sort()
        s = list(accumulate(nums, initial=0))  #Prefix sum
 
        def check(m):
            for i in range(m, n + 1):
                if nums[i - 1] * m - (s[i] - s[i - m]) <= k:
                    return True
            return False
 
        l, r = 1, n
        while l < r:
            mid = (l + r + 1) // 2
            if check(mid):
                l = mid
            else:
                r = mid - 1
        return l
 

Approach 2:

class Solution:
    def maxFrequency(self, nums: List[int], k: int) -> int:
        nums.sort()
        ans = 1
        s = j = 0
        for i in range(1, len(nums)):
            s += (nums[i] - nums[i - 1]) * (i - j)
            while s > k:
                s -= nums[i] - nums[j]
                j += 1
            ans = max(ans, i - j + 1)
        return ans

Both approaches achieve the correct result. Approach 2 might be slightly more efficient in practice due to the avoidance of binary search overhead, but both have the same theoretical time complexity. Choose the approach you find more readable and understandable.