3347. Maximum Frequency of an Element After Performing Operations II
Problem Description
You are given an integer array nums
and two integers k
and numOperations
. You need to perform an operation
numOperations
times on nums
, where in each operation you:
- Select an index
i
that was not selected in any previous operations. - Add an integer in the range
[-k, k]
tonums[i]
.
The task is to return the maximum possible frequency of any element in nums
after performing the operations.
Intuition
The problem revolves around maximizing the frequency of an integer in the array nums
through controlled modifications. Given the constraints, the idea is to adjust the values in nums
strategically by incrementing or decrementing them within the allowable range [−k, k]
to form duplicates and increase the frequency of a specific value.
-
Identify Potential Targets: Consider each unique number in
nums
as a potential target value whose frequency could be maximized. -
Difference Array Technique: Use the difference array technique where adjustments in the frequency count for potential values are computed. For each element
x
innums
, calculate the impact of the operation range[x − k, x + k]
by incrementing the positionx - k
and decrementing atx + k + 1
. -
Accumulating Changes: By sorting these impact points and accumulating the frequency changes, determine the maximum frequency achievable for any element. Adjust the count considering the operations allowed (
numOperations
), to find the highest frequency you can reach.
This approach efficiently evaluates how operations can be distributed to increase the frequency of one of the elements to the maximum possible degree, adhering to the constraints of the problem.
Learn more about Binary Search, Prefix Sum, Sorting and Sliding Window patterns.
Solution Approach
The solution employs a combination of a frequency counter and a difference array to optimize the operations across the nums
array. The implementation process is as follows:
-
Initialize Data Structures:
- Use
defaultdict
from thecollections
module to maintain counts of each number innums
(cnt
). - Another
defaultdict
is used to track the frequency changes caused by the range operations (d
).
- Use
-
Populate the Difference Array:
- Iterate over each number
x
innums
. - Increase the count for
x
in the frequency countercnt
to record its original occurrences. - Adjust the difference array
d
to incorporate the effect of adding numbers in the range[x−k, x+k]
. Specifically:- Increment
d[x − k]
to indicate that from this point, we will start adding potential frequency. - Decrement
d[x + k + 1]
to indicate that beyond this point, the addition effect ceases.
- Increment
- Iterate over each number
-
Calculate Maximum Frequency:
- Sort the difference array
d
by keys and iterate through it. - Use a variable
s
to accumulate ongoing frequency changes as derived fromd
. - For each point in this sorted list, update the running total
s
and compare to find the maximum frequency any number can achieve, taking into account the number of operations allowed (numOperations
). ans
keeps track of the maximum frequency encountered.
- Sort the difference array
-
Return Result:
- The algorithm concludes by returning the highest frequency (
ans
) that can be achieved after utilizing all possible operations efficiently.
- The algorithm concludes by returning the highest frequency (
This method effectively exploits the concept of treating range updates through a difference array pattern to maximize the occurrence of any given element, while smartly managing operations within their constraints.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's take a small example to illustrate the solution approach:
Suppose we have nums = [1, 2, 2, 3]
, k = 1
, and numOperations = 2
. Our goal is to maximize the frequency of any integer in nums
by adding a number in the range [-1, 1]
to any two indices.
-
Initialize Data Structures:
-
Start with a frequency counter
cnt
that tells us how many times each number currently appears:cnt = {1: 1, 2: 2, 3: 1}
-
Initialize a difference array
d
to record range effects:d = {}
-
-
Populate the Difference Array:
-
Traverse each element
x
innums
:-
x = 1
:
Incrementd[0]
(start of range for1-1
to1+1
), decrementd[2]
(end of range).d = {0: 1, 2: -1}
-
x = 2
:
Incrementd[1]
(start of range for2-1
to2+1
), decrementd[3]
(end of range).d = {0: 1, 1: 1, 2: -1, 3: -1}
-
x = 3
:
Incrementd[2]
(start of range for3-1
to3+1
), decrementd[4]
(end of range).d = {0: 1, 1: 1, 2: 0, 3: -1, 4: -1}
-
-
-
Calculate Maximum Frequency:
-
Sort
d
by keys and accumulate changes. Adjust with original counts fromcnt
:s = 0
,max_count = 0
- At position
0
:s = 1
, check if3
(count of1+2
operations) > currentmax_count
- At position
1
:s = 2
, possible frequency =2 + (2)
=4
- At position
2
:s = 2
- At position
3
:s = 1
, not better than4
-
The highest computed frequency is
4
when expanding around2
.
-
-
Return Result:
- The maximum achievable frequency after operations is
4
. This can be done by:- Changing two
3s
to2s
in the allowed operation range.
- Changing two
- The maximum achievable frequency after operations is
The solution strategically utilizes the difference array to effectively simulate range modifications, efficiently influencing frequency maximization across the array with given constraints.
Solution Implementation
1from collections import defaultdict
2from typing import List
3
4class Solution:
5 def maxFrequency(self, nums: List[int], k: int, numOperations: int) -> int:
6 # Dictionary to count the occurrences of each number in 'nums'
7 cnt = defaultdict(int)
8 # Difference array to help track the range manipulations
9 d = defaultdict(int)
10
11 # Populate 'cnt' and 'd' with the values from 'nums'
12 for x in nums:
13 cnt[x] += 1
14 # Mark the effect of starting an operation at 'x'
15 d[x] += 0
16 # Mark the start of range effects at 'x - k'
17 d[x - k] += 1
18 # Mark the end of range effects at 'x + k + 1'
19 d[x + k + 1] -= 1
20
21 ans = 0 # Initialize maximum frequency to zero
22 s = 0 # Initialize the prefix sum for the difference array
23
24 # Iterate over each key (x) in sorted order for the difference array
25 for x, t in sorted(d.items()):
26 s += t # Update the prefix sum
27 # Calculate the possible maximum frequency at this point
28 ans = max(ans, min(s, cnt[x] + numOperations))
29
30 return ans # Return the maximum frequency achieved
31
1import java.util.HashMap;
2import java.util.Map;
3import java.util.TreeMap;
4
5class Solution {
6 public int maxFrequency(int[] nums, int k, int numOperations) {
7 // Map for counting occurrences of each number
8 Map<Integer, Integer> numberCount = new HashMap<>();
9 // TreeMap to handle ranges and frequency adjustments
10 TreeMap<Integer, Integer> rangeAdjustments = new TreeMap<>();
11
12 // Populate maps with initial values
13 for (int num : nums) {
14 // Increment the count of the current number
15 numberCount.merge(num, 1, Integer::sum);
16 // If the number is not already in rangeAdjustments, add it with a default value
17 rangeAdjustments.putIfAbsent(num, 0);
18 // Adjust ranges for the number - k and number + k + 1
19 rangeAdjustments.merge(num - k, 1, Integer::sum);
20 rangeAdjustments.merge(num + k + 1, -1, Integer::sum);
21 }
22
23 int maxFrequency = 0; // Initialize variable to hold the maximum frequency found
24 int currentSum = 0; // Initialize variable for current frequency sum
25
26 // Iterate over the ranges to calculate the maximum frequency
27 for (var entry : rangeAdjustments.entrySet()) {
28 int value = entry.getKey(); // Current value in the range
29 int adjustment = entry.getValue(); // Current adjustment for the range
30
31 // Adjust current frequency sum based on the range
32 currentSum += adjustment;
33 // Calculate the maximum frequency considering current sum and allowed operations
34 int currentFrequency = Math.min(currentSum, numberCount.getOrDefault(value, 0) + numOperations);
35 maxFrequency = Math.max(maxFrequency, currentFrequency); // Update max frequency if higher
36 }
37
38 return maxFrequency; // Return the maximum frequency found
39 }
40}
41
1#include <vector>
2#include <unordered_map>
3#include <map>
4#include <algorithm>
5using namespace std;
6
7class Solution {
8public:
9 int maxFrequency(vector<int>& nums, int k, int numOperations) {
10 unordered_map<int, int> frequencyCount; // To count the frequency of each number.
11 map<int, int> balance; // Used for maintaining the balance of increments/decrements.
12
13 // For each number in nums, adjust the balance map.
14 for (int x : nums) {
15 frequencyCount[x]++; // Increment the count of current number.
16 balance[x]; // Ensure the current number x is a key in balance with default 0.
17
18 // Initiate a balance change at x-k and x+k+1
19 balance[x - k]++;
20 balance[x + k + 1]--;
21 }
22
23 int maxFrequency = 0; // Variable to store the maximum frequency found.
24 int currentSum = 0; // Current sum of balance to determine frequency.
25
26 // Iterate through the balance map, which is sorted by keys.
27 for (const auto& [value, type] : balance) {
28 currentSum += type; // Update the current sum with the balance type value.
29
30 // Determine max frequency by comparing:
31 // current operation sum with the frequency plus available operations.
32 maxFrequency = max(maxFrequency, min(currentSum, frequencyCount[value] + numOperations));
33 }
34
35 return maxFrequency; // Return the maximum frequency achievable.
36 }
37};
38
1/**
2 * This function calculates the maximum frequency of elements in an array
3 * that can be achieved by performing a limited number of operations.
4 * Each operation consists of incrementing or decrementing an element by a specified value k.
5 * @param nums - The array of numbers.
6 * @param k - The increment/decrement value for operations.
7 * @param numOperations - The total number of operations allowed.
8 * @returns The maximum frequency achievable.
9 */
10function maxFrequency(nums: number[], k: number, numOperations: number): number {
11 // To store frequency of each number in nums
12 const count: Record<number, number> = {};
13 // To manage the range additions/subtractions
14 const delta: Record<number, number> = {};
15
16 for (const x of nums) {
17 // Increment count for the current number
18 count[x] = (count[x] || 0) + 1;
19 // Initialize delta at current number if not already set
20 delta[x] = delta[x] || 0;
21 // Account for increment operation range start
22 delta[x - k] = (delta[x - k] || 0) + 1;
23 // Account for operation effect past end, decrement it
24 delta[x + k + 1] = (delta[x + k + 1] || 0) - 1;
25 }
26
27 // Initialize the maximum frequency found and a running sum
28 let maxFreq: number = 0;
29 let runningSum: number = 0;
30
31 // Sort keys in delta to process increments/decrements in order
32 const keys = Object.keys(delta).map(Number).sort((a, b) => a - b);
33
34 for (const key of keys) {
35 // Update running sum with delta change at this key
36 runningSum += delta[key];
37 // Calculate possible max frequency and update the maximum found
38 maxFreq = Math.max(maxFreq, Math.min(runningSum, (count[key] || 0) + numOperations));
39 }
40
41 return maxFreq;
42}
43
Time and Space Complexity
The time complexity of the given code is O(N log N)
, where N
is the number of elements in the nums
list. This comes primarily from the sorting operation on the dictionary d
items, which contains values derived from the list nums
.
The space complexity is O(N)
due to the use of the cnt
and d
dictionaries that store counts and modified counts for elements in nums
.
Learn more about how to find time and space complexity quickly.
What is the best way of checking if an element exists in a sorted array once in terms of time complexity? Select the best that applies.
Recommended Readings
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
Prefix Sum The prefix sum is an incredibly powerful and straightforward technique Its primary goal is to allow for constant time range sum queries on an array What is Prefix Sum The prefix sum of an array at index i is the sum of all numbers from index 0 to i By
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Want a Structured Path to Master System Design Too? Don’t Miss This!