3346. Maximum Frequency of an Element After Performing Operations I
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 objective is to maximize the frequency of some integer in nums
using at most numOperations
, each selecting a unique index and modifying the element at that index by adding an integer between -k
and k
. The approach involves considering the potential of each element within the array to increase its frequency, while ensuring the number of operations is not exceeded.
The solution leverages a counting mechanism to track the frequency of each number, and a differential array to efficiently compute the impact of adding values within the permissible range. By calculating the maximum frequency those numbers can reach when increased optimally with available operations, we can determine the highest possible frequency in the modified array.
Learn more about Binary Search, Prefix Sum, Sorting and Sliding Window patterns.
Solution Approach
The solution utilizes the concept of a frequency counter along with a differential array to determine the influence of operations on each element in nums
. Here’s a breakdown of the approach:
-
Initialize Data Structures:
- Use a
defaultdict
calledcnt
to store the initial frequency count of each number innums
. - Another
defaultdict
calledd
is used to maintain a differential array which helps in tracking how additions affect element frequency over its valid range[-k, k]
.
- Use a
-
Populate Frequency and Differential Arrays:
- Traverse each number
x
innums
. - Increase the count in the
cnt
dictionary for the numberx
to keep track of its initial frequency. - Use
d
to set up ranges influenced by additions:d[x]
remains unchanged and set as0
initially.- Increment
d[x - k]
because adding any number greater than or equal to-k
at position indexed byx
can start affecting this frequency. - Decrement the position
d[x + k + 1]
to signify the end of the influence of the addition once it exceeds the range[x-k, x+k]
.
- Traverse each number
-
Calculate Maximum Frequency:
- Initialize
ans
to 0 to store the result of the maximum frequency. - Traverse through the sorted keys of the differential array
d
, using a cumulative sum approach:- Add the current value of
t
(which represents the change) tos
, representing the current frequency influenced by operations. - Compute the maximum of
ans
andmin(s, cnt[x] + numOperations)
. This takes into account that the frequency can't exceed the sum of its initial count and the number of operations allowed.
- Add the current value of
- Initialize
-
Return the Result:
- Upon completion,
ans
holds the maximum achievable frequency of any number innums
after performing the specified operations.
- Upon completion,
This approach efficiently determines the optimal way to increase element frequencies while adhering to the constraint of allowed operations.
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 walk through an example to illustrate the solution approach using the given problem description.
Example
Consider the array nums = [1, 2, 2, 3]
with k = 1
and numOperations = 2
.
Step-by-Step Solution
-
Initialize Data Structures:
- Use a
defaultdict
namedcnt
to keep track of the initial frequencies:cnt = {1: 1, 2: 2, 3: 1}
- Set up another
defaultdict
namedd
to keep track of the differential array:d = {}
- Use a
-
Populate Frequency and Differential Arrays:
- Traverse each
x
innums
:- For
x = 1
, increment the positions:d[0] += 1 -> d = {0: 1} d[2] -= 1 -> d = {0: 1, 2: -1}
- For
x = 2
, increment and decrement the positions:d[1] += 1 -> d = {0: 1, 2: -1, 1: 1} d[3] -= 1 -> d = {0: 1, 2: -1, 1: 1, 3: -1}
- For
x = 3
, update positions similarly:d[2] += 1 -> d = {0: 1, 2: 0, 1: 1, 3: -1} d[4] -= 1 -> d = {0: 1, 2: 0, 1: 1, 3: -1, 4: -1}
- For
- Traverse each
-
Calculate Maximum Frequency:
- Initialize
ans
to0
for storing the maximum frequency. - Traverse sorted keys in
d
and compute cumulative sums:s = 0 (cumulative influence)
- For key
0
:t = 1 -> s = 1 max frequency = max(0, min(1, 1 + 2)) = 1
- For key
1
:t = 1 -> s = 2 max frequency = max(1, min(2, 2 + 2)) = 2
- For key
2
:t = 0 -> s = 2 (no change) max frequency = max(2, min(2, 2 + 2)) = 2
- For key
3
:t = -1 -> s = 1 max frequency = max(2, min(1, 1 + 2)) = 2
- Finally,
s
influences no further, adjustings
with subsequent keys.
- For key
- Initialize
-
Return the Result:
- The maximum achievable frequency is
2
, which can be a frequent number in the modified array after performing up tonumOperations
times.
- The maximum achievable frequency is
This example highlights using differential arrays and frequency counts to determine the most effective way to increase element frequencies within an integer array using specified 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 count = defaultdict(int) # Dictionary to store frequency of each number in nums
7 diff = defaultdict(int) # Dictionary to store difference adjustments
8
9 # Iterate over each number in nums
10 for x in nums:
11 count[x] += 1
12 # Increment count of x in 'count'
13
14 diff[x] += 0
15 # No change at point x for difference array
16
17 diff[x - k] += 1
18 # Start incrementing frequency deviation at (x - k)
19
20 diff[x + k + 1] -= 1
21 # Start decrementing frequency deviation at (x + k + 1)
22
23 maxFreq = 0
24 cumulativeSum = 0
25 # Initialize max frequency and cumulative sum to track diff changes
26
27 # Iterate over sorted keys of diff to simulate difference array adjustment
28 for x, change in sorted(diff.items()):
29 cumulativeSum += change
30 # Update cumulative sum with changes at current position
31
32 # Calculate possible maximum frequency with the limit of operations
33 maxFreq = max(maxFreq, min(cumulativeSum, count[x] + numOperations))
34
35 return maxFreq
36 # Return the maximum frequency achievable
37
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 // A map to count occurrences of each number in nums
8 Map<Integer, Integer> countMap = new HashMap<>();
9
10 // A TreeMap to keep track of increment and decrement operations
11 // at positions that are k intervals from each number
12 TreeMap<Integer, Integer> intervalChanges = new TreeMap<>();
13
14 // Populate the maps with data from nums
15 for (int num : nums) {
16 // Update countMap with the occurrence of each number
17 countMap.merge(num, 1, Integer::sum);
18
19 // Prepare intervalChanges for range operations
20 intervalChanges.putIfAbsent(num, 0);
21 intervalChanges.merge(num - k, 1, Integer::sum);
22 intervalChanges.merge(num + k + 1, -1, Integer::sum);
23 }
24
25 // Variables to hold the maximum frequency and sum of changes
26 int maxFrequency = 0;
27 int cumulativeChanges = 0;
28
29 // Iterate over the entries in intervalChanges
30 for (var entry : intervalChanges.entrySet()) {
31 int num = entry.getKey();
32 int change = entry.getValue();
33
34 // Update the cumulative changes as we move through the intervals
35 cumulativeChanges += change;
36
37 // Compute the possible maximum frequency at this number
38 // Consider if we can increase current count to at most available operations
39 int currentFrequency = Math.min(cumulativeChanges, countMap.getOrDefault(num, 0) + numOperations);
40
41 // Update the max frequency found
42 maxFrequency = Math.max(maxFrequency, currentFrequency);
43 }
44
45 return maxFrequency;
46 }
47}
48
1class Solution {
2public:
3 int maxFrequency(vector<int>& nums, int k, int numOperations) {
4 unordered_map<int, int> frequencyCount; // Map to count the frequency of each element in nums
5 map<int, int> differenceCount; // Map to track the difference in frequency at specific points
6
7 // Count the frequency of elements and prepare the difference map
8 for (int x : nums) {
9 frequencyCount[x]++; // Increment the count of current element
10 differenceCount[x]; // Initialize the difference map at this element (if not present)
11 differenceCount[x - k]++; // Mark a change at x-k
12 differenceCount[x + k + 1]--;// Mark a change at x+k+1 (counteract the change at x-k)
13 }
14
15 int answer = 0, sum = 0; // Initialize answer for the maximum frequency and a sum to track cumulative differences
16
17 // Iterate over each element in the difference map in a sorted manner
18 for (const auto& [x, change] : differenceCount) {
19 sum += change; // Update the cumulative difference
20 // Calculate the possible maximum frequency using the minimum operation constraint
21 answer = max(answer, min(sum, frequencyCount[x] + numOperations));
22 }
23
24 return answer; // Return the resulting maximum frequency
25 }
26};
27
1function maxFrequency(nums: number[], k: number, numOperations: number): number {
2 // To track the count of each number in the nums array
3 const cnt: Record<number, number> = {};
4 // To store the difference information for range updates
5 const d: Record<number, number> = {};
6
7 // Iterate through all numbers in the given array
8 for (const x of nums) {
9 // Increment the count of the current number
10 cnt[x] = (cnt[x] || 0) + 1;
11
12 // Initialize current value in d if not already present
13 d[x] = d[x] || 0;
14
15 // Update differential array for the range affected by operations
16 d[x - k] = (d[x - k] || 0) + 1;
17 d[x + k + 1] = (d[x + k + 1] || 0) - 1;
18 }
19
20 // Resultant maximum frequency and the accumulated effect of operations
21 let [ans, s] = [0, 0];
22
23 // Sort the keys of d to iterate in order
24 const keys = Object.keys(d).map(Number).sort((a, b) => a - b);
25
26 // Calculate the maximum frequency that can be achieved
27 for (const x of keys) {
28 // Update the accumulated value using differential values
29 s += d[x];
30
31 // Determine the maximum freq considering current segment
32 ans = Math.max(ans, Math.min(s, (cnt[x] || 0) + numOperations));
33 }
34
35 return ans; // Return the result
36}
37
Time and Space Complexity
The maxFrequency
function consists of several key parts that determine its computational complexity:
-
Initialization and Dictionary Population:
- Populating the dictionaries
cnt
andd
involves iterating over thenums
list, which takesO(n)
time wheren
is the length ofnums
.
- Populating the dictionaries
-
Sorting the Dictionary Items:
- Sorting the items of dictionary
d
takesO(m log m)
time, wherem
is the number of unique keys ind
.
- Sorting the items of dictionary
-
Processing the Sorted Items:
- Iterating through the sorted items of
d
takesO(m)
time.
- Iterating through the sorted items of
Overall, the time complexity becomes O(n + m log m)
.
Space Complexity Analysis
- The dictionaries
cnt
andd
each store up ton
entries in the worst case. Therefore, the space complexity isO(n)
.
Thus, the overall space complexity is O(n)
because of the usage of the dictionaries.
Learn more about how to find time and space complexity quickly.
What are the most two important steps in writing a depth first search function? (Select 2)
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!