Facebook Pixel

3085. Minimum Deletions to Make String K-Special

MediumGreedyHash TableStringCountingSorting
Leetcode Link

Problem Description

You are given a string word and an integer k.

We consider word to be k-special if |freq(word[i]) - freq(word[j])| <= k for all indices i and j in the string.

Here, freq(x) denotes the frequency of the character x in word, and |y| denotes the absolute value of y.

Return the minimum number of characters you need to delete to make word k-special.

Intuition

The problem boils down to adjusting the frequency of characters such that the difference between the maximum and minimum frequencies does not exceed k. Our task is to minimize deletions to achieve this.

  1. Counting Frequencies: First, count the frequency of each character. We represent these frequencies in an array nums.

  2. Enumeration Strategy: We attempt to find the "ideal" minimum frequency v within the range [0, n], where n is the length of word. This minimum frequency v helps us determine how much we need to delete to make the frequencies of characters differ by at most k.

  3. Function Calculation: For any chosen v, calculate the deletion count:

    • If a character occurs less than v, we delete all of its occurrences.
    • If a character's frequency exceeds v + k, we reduce it to v + k.

The overall approach is to explore all possible values of v and compute the number of deletions needed for each. The smallest number of deletions among these gives the desired result. This technique ensures that we find the minimal deletions necessary to satisfy the k-special conditions.

Learn more about Greedy and Sorting patterns.

Solution Approach

The primary goal of the solution is to efficiently determine the minimum number of deletions required to make the string k-special. Here's how it is achieved:

  1. Character Frequency Count: Use Python's Counter from the collections module to count the occurrences of each character in word. The frequencies are then extracted into a list nums.

  2. Enumeration of Minimum Frequency: Iterate over potential minimum frequencies, v, from 0 to n (the length of the word), to determine the minimal deletion strategy for each candidate v.

  3. Function f(v) Calculation:

    • The function f(v) is crafted to compute the number of deletions required for a given v.
    • For each frequency x in nums:
      • If x is less than v, all occurrences of the character contributing to this frequency are deleted.
      • If x exceeds v + k, reduce the frequency to v + k, resulting in deletions of x - v - k occurrences.
    • The function accumulates the total deletions needed based on these rules.
  4. Result Extraction: The answer is the minimum value obtained from evaluating f(v) over all possible v. This represents the fewest deletions needed to satisfy the k-special condition for word.

By evaluating every viable v, the algorithm swiftly identifies the optimal frequency range adjustments required to achieve balance among character frequencies within the constraints of k.

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 consider the string word = "aabbcc" and k = 1.

Step 1: Character Frequency Count

Using Python's collections.Counter, we count the frequency of each character in word. This results in:

  • a appears 2 times
  • b appears 2 times
  • c appears 2 times

Thus, the frequency list nums becomes [2, 2, 2].

Step 2: Enumeration of Minimum Frequency

We evaluate potential minimum frequencies v from 0 to 6 (the length of the word word).

Step 3: Function f(v) Calculation

For each v, calculate the necessary deletions:

  • If v = 0:

    • All characters already have frequency greater than 0.
    • No deletions are needed because the condition |freq(word[i]) - freq(word[j])| <= 1 is already satisfied.
  • If v = 1:

    • No deletion for any character as all frequencies are either 1 or 1 + k = 2.
    • Total deletions: 0
  • If v = 2:

    • Again, no deletions are needed because all frequencies match v exactly.
    • Total deletions: 0

All frequencies from v = 0 to v = 2 already satisfy the k-special condition with zero deletions.

Step 4: Result Extraction

The minimum deletions required across all v is 0. Thus, 0 deletions are needed to make word k-special with k = 1.

By considering how frequencies align with possible v values, this method effectively determines minimal adjustments necessary to satisfy the problem constraints.

Solution Implementation

1from collections import Counter
2
3class Solution:
4    def minimumDeletions(self, word: str, k: int) -> int:
5        # Inner function to calculate the minimum deletions required for a given threshold
6        def f(threshold: int) -> int:
7            deletions = 0
8            for frequency in frequencies:
9                # If frequency is less than the threshold, we need to delete all occurrences
10                if frequency < threshold:
11                    deletions += frequency
12                # If frequency is greater than the threshold plus k, delete the excess
13                elif frequency > threshold + k:
14                    deletions += frequency - threshold - k
15            return deletions
16
17        # Get a list of the frequencies of each character in the word
18        frequencies = Counter(word).values()
19        # Calculate and return the minimum deletions for all possible threshold values
20        return min(f(threshold) for threshold in range(len(word) + 1))
21
1import java.util.ArrayList;
2import java.util.List;
3
4class Solution {
5    // List to store the frequencies of characters in the input word
6    private List<Integer> characterFrequencies = new ArrayList<>();
7
8    // Method to calculate the minimum number of deletions required
9    public int minimumDeletions(String word, int k) {
10        // Array to store frequency of each character in the English alphabet
11        int[] frequencyArray = new int[26];
12        int wordLength = word.length();
13      
14        // Calculate frequency of each character in the input word
15        for (int i = 0; i < wordLength; ++i) {
16            ++frequencyArray[word.charAt(i) - 'a'];
17        }
18      
19        // Add non-zero frequencies to the characterFrequencies list
20        for (int frequency : frequencyArray) {
21            if (frequency > 0) {
22                characterFrequencies.add(frequency);
23            }
24        }
25      
26        // Initialize the answer with the length of the word
27        int minimumDeletions = wordLength;
28      
29        // Find the minimum deletions possible by checking for every potential value `v` from 0 to word length
30        for (int i = 0; i <= wordLength; ++i) {
31            // Update minimumDeletions with the smaller value between the current and the new calculation from helper function `f`
32            minimumDeletions = Math.min(minimumDeletions, calculateDeletions(i, k));
33        }
34        return minimumDeletions;
35    }
36
37    // Helper method to calculate deletions given a threshold `v` and limit `k`
38    private int calculateDeletions(int v, int k) {
39        int deletions = 0;
40      
41        // Iterate over each frequency in the list
42        for (int frequency : characterFrequencies) {
43            // If the frequency is less than `v`, add the full frequency to deletions
44            if (frequency < v) {
45                deletions += frequency;
46            }
47            // If the frequency exceeds `v + k`, calculate the deletions needed to reduce it
48            else if (frequency > v + k) {
49                deletions += frequency - v - k;
50            }
51        }
52        return deletions;
53    }
54}
55
1#include <vector>
2#include <string>
3#include <algorithm>  // For std::min
4using namespace std;
5
6class Solution {
7public:
8    int minimumDeletions(string word, int k) {
9        // Array to store the frequency of each character in the word.
10        int frequency[26] = {};
11
12        // Increment the appropriate frequency count for each character in 'word'.
13        for (char& c : word) {
14            ++frequency[c - 'a'];
15        }
16
17        // Vector to store the frequencies of all the characters that appear in the word.
18        vector<int> characterFrequencies;
19        for (int freq : frequency) {
20            if (freq > 0) {
21                characterFrequencies.push_back(freq);
22            }
23        }
24
25        int wordSize = word.size();
26        int minimumDeletionsResult = wordSize;
27
28        // Lambda function to calculate deletions needed to balance frequencies.
29        auto calculateDeletions = [&](int targetFrequency) {
30            int deletions = 0;
31            for (int freq : characterFrequencies) {
32                if (freq < targetFrequency) {  // Frequency is too low
33                    deletions += freq;
34                } else if (freq > targetFrequency + k) {  // Frequency too high to be adjusted by 'k'
35                    deletions += (freq - targetFrequency - k);
36                }
37            }
38            return deletions;
39        };
40
41        // Try all target frequencies from 0 to the size of the word to determine minimum deletions.
42        for (int target = 0; target <= wordSize; ++target) {
43            minimumDeletionsResult = min(minimumDeletionsResult, calculateDeletions(target));
44        }
45
46        return minimumDeletionsResult;
47    }
48};
49
1// Function to calculate the minimum number of deletions required from the word
2// such that for any character frequency `x`, either `x < v` or `x > v + k`
3function minimumDeletions(word: string, k: number): number {
4    // Create an array to store the frequency of each letter in the word
5    const frequency: number[] = Array(26).fill(0);
6  
7    // Populate the frequency array
8    for (const ch of word) {
9        frequency[ch.charCodeAt(0) - 97]++;
10    }
11  
12    // Filter out zero frequencies, only keep those greater than zero
13    const nums = frequency.filter(count => count > 0);
14  
15    // Helper function to calculate deletions needed for a given target value v
16    const f = (v: number): number => {
17        let deletions = 0;
18        for (const x of nums) {
19            if (x < v) {
20                deletions += x;
21            } else if (x > v + k) {
22                deletions += x - v - k;
23            }
24        }
25        return deletions;
26    };
27  
28    // Calculate the minimum deletions required by considering all possible target frequencies
29    return Math.min(...Array.from({ length: word.length + 1 }, (_, i) => f(i)));
30}
31

Time and Space Complexity

The time complexity of the code is O(n ร— |\Sigma|) because for each unique character frequency in the word, which can be at most n, we are iterating over a range of size n + 1 and calculating the function f(v), which is O(|\Sigma|). Since |\Sigma| is limited to 26 in this particular problem, this results in a linear time complexity relative to the length of the word.

The space complexity of the code is O(|\Sigma|) because we use a Counter to store the frequency of each character in the word, which uses space proportional to the size of the character set, |\Sigma|, which is at most 26.

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

How many times is a tree node visited in a depth first search?


Recommended Readings

Want a Structured Path to Master System Design Too? Donโ€™t Miss This!


Load More