1838. Frequency of The Most Frequent Element - Explanation
Description
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: 3Explanation: 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: 2Explanation: 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.
Constraints:
1 <= nums.length <= 100,0001 <= nums[i], k <= 100,000
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Sorting - Arranging elements to enable efficient window-based approaches
- Sliding Window - Maintaining a dynamic window with adjustable boundaries
- Prefix Sum - Efficiently computing range sums for cost calculations
- Binary Search - Finding optimal boundaries in sorted data
- Greedy Reasoning - Understanding why the target value must exist in the original array
1. Brute Force
Intuition
We can only increment elements, so the target value for our frequent element must already exist in the array. For each element, we check how many smaller elements we can increment to match it using at most k operations.
Sorting the array helps because the elements closest in value to our target require the fewest increments. We greedily extend leftward from each position, incrementing elements until we run out of operations.
Algorithm
- Sort the array in ascending order.
- For each index
i, treatnums[i]as the target value. - Starting from
j = i - 1, work backward and subtract the costnums[i] - nums[j]from a temporary budget. - Stop when the budget becomes negative.
- The count of elements matching
nums[i]isi - j. - Track and return the maximum count found in
res.
Time & Space Complexity
- Time complexity:
- Space complexity: or depending on the sorting algorithm.
2. Prefix Sum + Binary Search
Intuition
Instead of extending leftward one element at a time, we can use binary search to find the optimal left boundary. The cost to make all elements in a range equal to the rightmost element is: (count * target) - sum_of_range. Using prefix sums, we compute range sums in O(1).
For each right boundary i, we binary search for the smallest left boundary m such that the cost is within budget k. The window size i - m + 1 gives us the frequency.
Algorithm
- Sort the array and build a prefix sum array.
- For each index
i:- Binary search for the leftmost index
mwhere the cost(i - m + 1) * nums[i] - (prefix[i+1] - prefix[m])is at mostk. - Update
reswith the window size.
- Binary search for the leftmost index
- Return the maximum frequency found.
class Solution:
def maxFrequency(self, nums: List[int], k: int) -> int:
nums.sort()
n = len(nums)
prefix_sum = [0] * (n + 1)
for i in range(n):
prefix_sum[i + 1] = prefix_sum[i] + nums[i]
res = 1
for i in range(n):
l, r = 0, i
while l <= r:
m = (l + r) // 2
curSum = prefix_sum[i + 1] - prefix_sum[m]
need = (i - m + 1) * nums[i] - curSum
if need <= k:
r = m - 1
res = max(res, i - m + 1)
else:
l = m + 1
return resTime & Space Complexity
- Time complexity:
- Space complexity:
3. Sliding Window
Intuition
Since the array is sorted, we can use a sliding window. As we expand the window by moving the right pointer, we add elements and check if the cost to make all elements equal to the rightmost exceeds k. If it does, we shrink from the left.
The cost for a window is target * window_size - window_sum. When this exceeds k, we need a smaller window. The window always represents a valid subarray that can be made uniform within budget.
Algorithm
- Sort the array.
- Initialize
l = 0,total = 0, andres = 0. - For each right index
r:- Add
nums[r]tototal. - While
nums[r] * (r - l + 1) > total + k:- Subtract
nums[l]fromtotaland incrementl.
- Subtract
- Update
reswithr - l + 1.
- Add
- Return
res.
Time & Space Complexity
- Time complexity:
- Space complexity: or depending on the sorting algorithm.
4. Advanced Sliding Window
Intuition
We can optimize further by observing that we only care about the maximum window size. Once we find a valid window of size w, we never need a smaller window. So instead of shrinking until valid, we can just slide the window forward, maintaining its size when invalid.
If a new element causes the window to become invalid, we remove exactly one element from the left, keeping the window size the same. The window size only grows when we find a valid configuration.
Algorithm
- Sort the array.
- Initialize
l = 0andtotal = 0. - For each right index
r:- Add
nums[r]tototal. - If
(r - l + 1) * nums[r] > total + k:- Subtract
nums[l]fromtotaland incrementl.
- Subtract
- Add
- The final window size is
n - lwhich equals the maximum frequency. - Return this value.
Time & Space Complexity
- Time complexity:
- Space complexity: or depending on the sorting algorithm.
Common Pitfalls
Forgetting to Sort the Array
The sliding window and binary search approaches only work on a sorted array. Without sorting, elements that could be incremented to match a target value are scattered throughout the array, making it impossible to find contiguous windows efficiently. Always sort first before applying the window techniques.
Integer Overflow in Cost Calculation
When calculating the cost (window_size) * target - window_sum, the multiplication can overflow if using 32-bit integers. For large arrays with values up to 10^5, the product can exceed 2^31. Use long or long long for the total variable and cast appropriately before multiplication.
Incorrect Window Shrinking Condition
A common mistake is using >= instead of > when checking if the window is invalid. The condition should be nums[r] * (r - l + 1) > total + k (strictly greater), not >=. Using >= would shrink valid windows prematurely, potentially missing the optimal answer.
Sign in to join the discussion