Facebook Pixel

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] to nums[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.

  1. Identify Potential Targets: Consider each unique number in nums as a potential target value whose frequency could be maximized.

  2. Difference Array Technique: Use the difference array technique where adjustments in the frequency count for potential values are computed. For each element x in nums, calculate the impact of the operation range [x − k, x + k] by incrementing the position x - k and decrementing at x + k + 1.

  3. 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:

  1. Initialize Data Structures:

    • Use defaultdict from the collections module to maintain counts of each number in nums (cnt).
    • Another defaultdict is used to track the frequency changes caused by the range operations (d).
  2. Populate the Difference Array:

    • Iterate over each number x in nums.
    • Increase the count for x in the frequency counter cnt 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.
  3. 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 from d.
    • 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.
  4. Return Result:

    • The algorithm concludes by returning the highest frequency (ans) that can be achieved after utilizing all possible operations efficiently.

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 Evaluator

Example 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.

  1. 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 = {}
  2. Populate the Difference Array:

    • Traverse each element x in nums:

      • x = 1:
        Increment d[0] (start of range for 1-1 to 1+1), decrement d[2] (end of range).

        d = {0: 1, 2: -1}
      • x = 2:
        Increment d[1] (start of range for 2-1 to 2+1), decrement d[3] (end of range).

        d = {0: 1, 1: 1, 2: -1, 3: -1}
      • x = 3:
        Increment d[2] (start of range for 3-1 to 3+1), decrement d[4] (end of range).

        d = {0: 1, 1: 1, 2: 0, 3: -1, 4: -1}
  3. Calculate Maximum Frequency:

    • Sort d by keys and accumulate changes. Adjust with original counts from cnt:

      • s = 0, max_count = 0
      • At position 0: s = 1, check if 3 (count of 1+2 operations) > current max_count
      • At position 1: s = 2, possible frequency = 2 + (2) = 4
      • At position 2: s = 2
      • At position 3: s = 1, not better than 4
    • The highest computed frequency is 4 when expanding around 2.

  4. Return Result:

    • The maximum achievable frequency after operations is 4. This can be done by:
      • Changing two 3s to 2s in the allowed operation range.

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.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

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

Want a Structured Path to Master System Design Too? Don’t Miss This!


Load More