Open In App

Check if frequency of all characters can become same by one removal

Given a string that contains lower alphabetic characters, we need to remove at most one character from this string in such a way that frequency of each distinct character becomes the same in the string.

Examples:  

Input: str = “xyyz” 
Output: Yes 
We can remove character ’y’ from above 
string to make the frequency of each 
character same. 

Input: str = “xyyzz” 
Output: Yes 
We can remove character ‘x’ from above 
string to make the frequency of each 
character same.

Input: str = “xxxxyyzz” 
Output: No 
It is not possible to make frequency of 
each character same just by removing at 
most one character from above string.

Approach: The problem can be solved using the concept of hashing. The main thing to observe in this problem is that the position of characters does not matter here so we will count the frequency of characters, if all of them are the same then we are done and there is no need to remove any character to make frequency of characters same Otherwise we can iterate over all characters one by one and decrease their frequency by one, if all frequencies become same then we will flag that it is possible to make character frequency same by at most one removal and if frequencies don’t match then we will increase that frequency again and loop for other characters. 

Below is a dry run of the above approach: 

Below is the implementation of the above approach:

// C++ program to get same frequency character
// string by removal of at most one char
#include <bits/stdc++.h>
using namespace std;
#define M 26

// Utility method to get index of character ch
// in lower alphabet characters
int getIdx(char ch)
{
    return (ch - 'a');
}

// Returns true if all non-zero elements
// values are same
bool allSame(int freq[], int N)
{
    int same;

    // get first non-zero element
    int i;
    for (i = 0; i < N; i++) {
        if (freq[i] > 0) {
            same = freq[i];
            break;
        }
    }

    // check equality of each element with variable same
    for (int j = i + 1; j < N; j++)
        if (freq[j] > 0 && freq[j] != same)
            return false;

    return true;
}

// Returns true if we can make all character
// frequencies same
bool possibleSameCharFreqByOneRemoval(string str)
{
    int l = str.length();

    // fill frequency array
    int freq[M] = { 0 };
    for (int i = 0; i < l; i++)
        freq[getIdx(str[i])]++;

    // if all frequencies are same, then return true
    if (allSame(freq, M))
        return true;

    /*  Try decreasing frequency of all character
        by one and then    check all equality of all
        non-zero frequencies */
    for (char c = 'a'; c <= 'z'; c++) {
        int i = getIdx(c);

        // Check character only if it occurs in str
        if (freq[i] > 0) {
            freq[i]--;

            if (allSame(freq, M))
                return true;
            freq[i]++;
        }
    }

    return false;
}

// Driver code to test above methods
int main()
{
    string str = "xyyzz";
    if (possibleSameCharFreqByOneRemoval(str))
        cout << "Yes";
    else
        cout << "No";
}
// Java program to get same frequency character
// string by removal of at most one char
public class GFG {

    static final int M = 26;

    // Utility method to get index of character ch
    // in lower alphabet characters
    static int getIdx(char ch)
    {
        return (ch - 'a');
    }

    // Returns true if all non-zero elements
    // values are same
    static boolean allSame(int freq[], int N)
    {
        int same = 0;

        // get first non-zero element
        int i;
        for (i = 0; i < N; i++) {
            if (freq[i] > 0) {
                same = freq[i];
                break;
            }
        }

        // check equality of each element with
        // variable same
        for (int j = i + 1; j < N; j++)
            if (freq[j] > 0 && freq[j] != same)
                return false;

        return true;
    }

    // Returns true if we can make all character
    // frequencies same
    static boolean possibleSameCharFreqByOneRemoval(String str)
    {
        int l = str.length();

        // fill frequency array
        int[] freq = new int[M];

        for (int i = 0; i < l; i++)
            freq[getIdx(str.charAt(i))]++;

        // if all frequencies are same, then return true
        if (allSame(freq, M))
            return true;

        /*  Try decreasing frequency of all character
            by one and then check all equality of all
            non-zero frequencies */
        for (char c = 'a'; c <= 'z'; c++) {
            int i = getIdx(c);

            // Check character only if it occurs in str
            if (freq[i] > 0) {
                freq[i]--;

                if (allSame(freq, M))
                    return true;
                freq[i]++;
            }
        }

        return false;
    }

    // Driver code to test above methods
    public static void main(String args[])
    {
        String str = "xyyzz";
        if (possibleSameCharFreqByOneRemoval(str))
            System.out.println("Yes");
        else
            System.out.println("No");
    }
}
// This code is contributed by Sumit Ghosh
# Python3 program to get same frequency character 
# string by removal of at most one char
M = 26

# Utility method to get index of character ch 
# in lower alphabet characters 
def getIdx(ch):
    return (ord(ch) - ord('a'))

# Returns true if all non-zero elements 
# values are same 
def allSame(freq, N):
    
    # get first non-zero element 
    for i in range(0, N):
        if(freq[i] > 0):
            same = freq[i]
            break
        
    # check equality of each element 
    # with variable same     
    for j in range(i + 1, N):
        if(freq[j] > 0 and freq[j] != same):
            return False

    return True

# Returns true if we can make all 
# character frequencies same 
def possibleSameCharFreqByOneRemoval(str1):
    l = len(str1)

    # fill frequency array
    freq = [0] * M
    for i in range(0, l):
        freq[getIdx(str1[i])] += 1
        
    # if all frequencies are same, 
    # then return true 
    if(allSame(freq, M)):
        return True
    
    # Try decreasing frequency of all character 
    # by one and then check all equality of all 
    # non-zero frequencies 
    for i in range(0, 26):
        
        # Check character only if it 
        # occurs in str 
        if(freq[i] > 0):
            freq[i] -= 1

            if(allSame(freq, M)):
                return True
            freq[i] += 1

    return False

# Driver code
if __name__ == "__main__":
    str1 = "xyyzz"
    if(possibleSameCharFreqByOneRemoval(str1)):
        print("Yes")
    else:
        print("No")

# This code is contributed by Sairahul099
// C# program to get same frequency
// character string by removal of
// at most one char
using System;

class GFG {
    static int M = 26;

    // Utility method to get
    // index of character ch
    // in lower alphabet characters
    static int getIdx(char ch)
    {
        return (ch - 'a');
    }

    // Returns true if all
    // non-zero elements
    // values are same
    static bool allSame(int[] freq,
                        int N)
    {
        int same = 0;

        // get first non-zero element
        int i;
        for (i = 0; i < N; i++) {
            if (freq[i] > 0) {
                same = freq[i];
                break;
            }
        }

        // check equality of
        // each element with
        // variable same
        for (int j = i + 1; j < N; j++)
            if (freq[j] > 0 && freq[j] != same)
                return false;

        return true;
    }

    // Returns true if we
    // can make all character
    // frequencies same
    static bool possibleSameCharFreqByOneRemoval(string str)
    {
        int l = str.Length;

        // fill frequency array
        int[] freq = new int[M];

        for (int i = 0; i < l; i++)
            freq[getIdx(str[i])]++;

        // if all frequencies are same,
        // then return true
        if (allSame(freq, M))
            return true;

        /* Try decreasing frequency of all 
            character by one and then check 
            all equality of all non-zero 
            frequencies */
        for (char c = 'a'; c <= 'z'; c++) {
            int i = getIdx(c);

            // Check character only if
            // it occurs in str
            if (freq[i] > 0) {
                freq[i]--;

                if (allSame(freq, M))
                    return true;
                freq[i]++;
            }
        }

        return false;
    }

    // Driver code
    public static void Main()
    {
        string str = "xyyzz";
        if (possibleSameCharFreqByOneRemoval(str))
            Console.Write("Yes");
        else
            Console.Write("No");
    }
}

// This code is contributed
// by ChitraNayal
<script>

// Javascript program to get same 
// frequency character string by 
// removal of at most one char
let  M = 26;

// Utility method to get index of character 
// ch in lower alphabet characters
function getIdx(ch)
{
    return (ch - 'a');
}

// Returns true if all non-zero elements
// values are same
function allSame(freq, N)
{
    let same = 0;

    // Get first non-zero element
    let i;
    for(i = 0; i < N; i++)
    {
        if (freq[i] > 0)
        {
            same = freq[i];
            break;
        }
    }

    // Check equality of each element with
    // variable same
    for(let j = i + 1; j < N; j++)
        if (freq[j] > 0 && freq[j] != same)
            return false;

    return true;
}

// Returns true if we can make all character
// frequencies same
function possibleSameCharFreqByOneRemoval(str)
{
    let l = str.length;

    // Fill frequency array
    let freq = new Array(M);
    for(let i = 0; i < M; i++)
    {
        freq[i] = 0;
    }

    for(let i = 0; i < l; i++)
        freq[getIdx(str[i])]++;

    // If all frequencies are same, 
    // then return true
    if (allSame(freq, M))
        return true;

    // Try decreasing frequency of all character
    // by one and then check all equality of all
    // non-zero frequencies 
    for(let c = 'a'; c <= 'z'; c++) 
    {
        let i = getIdx(c);

        // Check character only if 
        // it occurs in str
        if (freq[i] > 0) 
        {
            freq[i]--;

            if (allSame(freq, M))
                return true;
                
            freq[i]++;
        }
    }
    return false;
}

// Driver code 
let str = "xyyzz";

if (possibleSameCharFreqByOneRemoval(str))
    document.write("Yes");
else
    document.write("No");

// This code is contributed by avanitrachhadiya2155

</script>
<?php 
// PHP program to get same frequency 
// character string by removal of at 
// most one char
$M = 26;

// Utility method to get index 
// of character ch in lower 
// alphabet characters
function getIdx($ch)
{
    return ($ch - 'a');
}

// Returns true if all 
// non-zero elements
// values are same
function allSame(&$freq, $N)
{
    // get first non-zero element
    for ($i = 0; $i < $N; $i++)
    {
        if ($freq[$i] > 0)
        {
            $same = $freq[$i];
            break;
        }
    }

    // check equality of each
    // element with variable same
    for ($j = $i + 1; $j < $N; $j++)
        if ($freq[$j] > 0 && 
            $freq[$j] != $same)
            return false;

    return true;
}

// Returns true if we
// can make all character
// frequencies same
function possibleSameCharFreqByOneRemoval($str)
{
    global $M;
    $l = strlen($str);

    // fill frequency array
    $freq = array_fill(0, $M, NULL);
    for ($i = 0; $i < $l; $i++)
        $freq[getIdx($str[$i])]++;

    // if all frequencies are same, 
    // then return true
    if (allSame($freq, $M))
        return true;

    /* Try decreasing frequency of all 
        character by one and then check 
        all equality of all non-zero 
        frequencies */
    for ($c = 'a'; $c <= 'z'; $c++)
    {
        $i = getIdx($c);

        // Check character only 
        // if it occurs in str
        if ($freq[$i] > 0)
        {
            $freq[$i]--;

            if (allSame($freq, $M))
                return true;
            $freq[$i]++;
        }
    }

    return false;
}

// Driver code
$str = "xyyzz";
if (possibleSameCharFreqByOneRemoval($str))
echo "Yes";
else
echo "No";

// This code is contributed 
// by ChitraNayal
?>

Output
Yes

Time Complexity: O(n) assuming alphabet size is constant. 
Auxiliary Space: O(1)

Alternate way to solve this problem using Collections framework:

In this approach we are going to use Collection class to solve the given problem. 

Steps-by-step algorithm:

  1. First we will take 2 hashmap. One will used to store character and its count and another will stored the count  of occurrence of character and number to character which having same count.
  2. After this if 2nd hashmap size is 1 that means character frequency is one so we simply return true.
  3. Now we will declare 2 arraylist to store key in one arraylist and values in another list.
  4. Now we will check if it is possible to make frequency of character by one removal or not. If yes then return true else return false. 

Below is the implementation of the above approach:

#include <bits/stdc++.h>
using namespace std;

bool sameFreq(string s)
{
    // create two empty maps for storing character
    // frequencies and frequency counts
    map<char, int> h;
    map<int, int> a;

    // iterate through each character in the input string
    for (int i = 0; i < s.length(); i++)
    {
      
        // increment the count for the current character in
        // the frequency map
        h[s[i]]++;
    }

    // iterate through each key-value pair in the frequency
    // map
    for (auto map : h) {
        // increment the count for the current frequency in
        // the frequency count map
        a[map.second]++;
    }

    // check if there is only one unique frequency count
    if (a.size() == 1) {
        return true;
    }
    // check if there are only two unique frequency counts
    else if (a.size() == 2) {
        vector<int> list;
        vector<int> l;

        // iterate through each key-value pair in the
        // frequency count map
        for (auto entry : a) {
            int key = entry.first;
            int value = entry.second;

            // add the current frequency and frequency count
            // to their respective vectors
            list.push_back(key);
            l.push_back(value);
        }

        // check if there is a single occurrence of a
        // frequency count of 1
        if ((list[1] == 1 && l[1] == 1)
            || (list[0] == 1 && l[0] == 1)) {
            return true;
        }
        // check if the difference between the two frequency
        // counts is 1
        else if (abs(list[1] - list[0]) == 1) {
            return true;
        }
        else {
            return false;
        }
    }
    else {
        return false;
    }
}

int main()
{
    string str = "xxxyyz";
    if (sameFreq(str)) {
        cout << "YES" << endl;
    }
    else {
        cout << "NO" << endl;
    }

    return 0;
}
import java.util.*;
public class HelloWorld {
    
       static public boolean sameFreq(String s) {
        HashMap<Character, Integer> h = new HashMap<>();
        HashMap<Integer, Integer> a = new HashMap<>();
        
        for(int i = 0; i<s.length(); i++)
        {
            h.put(s.charAt(i), h.getOrDefault(s.charAt(i), 0)+1);
        }
        
        for (Map.Entry<Character, Integer> map : h.entrySet()) {
            a.put(map.getValue(), a.getOrDefault(map.getValue(), 0)+1);
        }
        
        if(a.size() == 1)
        {
            return true;
        }
        if(a.size() == 2)
        {
            ArrayList<Integer> list = new ArrayList<>();
            ArrayList<Integer> l = new ArrayList<>();
            
            for (Map.Entry<Integer, Integer> entry : a.entrySet()) {
                Integer key = entry.getKey();
                Integer value = entry.getValue();
                
                list.add(key);
                l.add(value);
            }
            
            if((list.get(1) == 1 && l.get(1) == 1) || (list.get(0) == 1 && l.get(0) == 1)) {
                return true;
            }
            
            else if(Math.abs(list.get(1) - list.get(0)) == 1) {
                return true;
            }
            else
            {
                return false;
            }
            
        }
        else
        {
            return false;
        }
    }
    public static void main(String[] args)
    {
        String str="xxxyyz";
        if(sameFreq(str)){
            System.out.println("YES");
        }else{
            System.out.println("NO");
        }
    }
}
 
def sameFreq(s):
    # create two empty dictionaries for storing character
    # frequencies and frequency counts
    h = {}
    a = {}

    # iterate through each character in the input string
    for i in s:
        # increment the count for the current character in
        # the frequency dictionary
        h[i] = h.get(i, 0) + 1

    # iterate through each key-value pair in the frequency
    # dictionary
    for key, value in h.items():
        # increment the count for the current frequency in
        # the frequency count dictionary
        a[value] = a.get(value, 0) + 1

    # check if there is only one unique frequency count
    if len(a) == 1:
        return True
    # check if there are only two unique frequency counts
    elif len(a) == 2:
        l = []
        list = []

        # iterate through each key-value pair in the
        # frequency count dictionary
        for key, value in a.items():
            # add the current frequency and frequency count
            # to their respective lists
            list.append(key)
            l.append(value)

        # check if there is a single occurrence of a
        # frequency count of 1
        if (list[1] == 1 and l[1] == 1) or (list[0] == 1 and l[0] == 1):
            return True
        # check if the difference between the two frequency
        # counts is 1
        elif abs(list[1] - list[0]) == 1:
            return True
        else:
            return False
    else:
        return False

str = "xxxyyz"
if sameFreq(str):
    print("YES")
else:
    print("NO")
using System;
using System.Collections.Generic;

class Program {
    static bool SameFreq(string s)
    {
        // create two empty dictionaries for storing
        // character frequencies and frequency counts
        Dictionary<char, int> h
            = new Dictionary<char, int>();
        Dictionary<int, int> a = new Dictionary<int, int>();

        // iterate through each character in the input
        // string
        foreach(char c in s)
        {
            // increment the count for the current character
            // in the frequency dictionary
            if (h.ContainsKey(c)) {
                h[c]++;
            }
            else {
                h.Add(c, 1);
            }
        }

        // iterate through each key-value pair in the
        // frequency dictionary
        foreach(KeyValuePair<char, int> kvp in h)
        {
            // increment the count for the current frequency
            // in the frequency count dictionary
            if (a.ContainsKey(kvp.Value)) {
                a[kvp.Value]++;
            }
            else {
                a.Add(kvp.Value, 1);
            }
        }

        // check if there is only one unique frequency count
        if (a.Count == 1) {
            return true;
        }
        // check if there are only two unique frequency
        // counts
        else if (a.Count == 2) {
            List<int> list = new List<int>();
            List<int> l = new List<int>();

            // iterate through each key-value pair in the
            // frequency count dictionary
            foreach(KeyValuePair<int, int> kvp in a)
            {
                int key = kvp.Key;
                int value = kvp.Value;

                // add the current frequency and frequency
                // count to their respective lists
                list.Add(key);
                l.Add(value);
            }

            // check if there is a single occurrence of a
            // frequency count of 1
            if ((list[1] == 1 && l[1] == 1)
                || (list[0] == 1 && l[0] == 1)) {
                return true;
            }
            // check if the difference between the two
            // frequency counts is 1
            else if (Math.Abs(list[1] - list[0]) == 1) {
                return true;
            }
            else {
                return false;
            }
        }
        else {
            return false;
        }
    }

    static void Main(string[] args)
    {
        string str = "xxxyyz";
        if (SameFreq(str)) {
            Console.WriteLine("YES");
        }
        else {
            Console.WriteLine("NO");
        }
    }
}
// This code is contributed by Prajwal Kandekar
function sameFreq(s) {
    // create two empty maps for storing character
    // frequencies and frequency counts
    let h = new Map();
    let a = new Map();

    // iterate through each character in the input string
    for (let i = 0; i < s.length; i++) {
        // increment the count for the current character in
        // the frequency map
        h.set(s[i], (h.get(s[i]) || 0) + 1);
    }

    // iterate through each key-value pair in the frequency
    // map
    for (let [key, value] of h) {
        // increment the count for the current frequency in
        // the frequency count map
        a.set(value, (a.get(value) || 0) + 1);
    }

    // check if there is only one unique frequency count
    if (a.size === 1) {
        return true;
    }
    // check if there are only two unique frequency counts
    else if (a.size === 2) {
        let list = [];
        let l = [];

        // iterate through each key-value pair in the
        // frequency count map
        for (let [key, value] of a) {
            // add the current frequency and frequency count
            // to their respective vectors
            list.push(key);
            l.push(value);
        }

        // check if there is a single occurrence of a
        // frequency count of 1
        if ((list[1] === 1 && l[1] === 1)
            || (list[0] === 1 && l[0] === 1)) {
            return true;
        }
        // check if the difference between the two frequency
        // counts is 1
        else if (Math.abs(list[1] - list[0]) === 1) {
            return true;
        }
        else {
            return false;
        }
    }
    else {
        return false;
    }
}

let str = "xxxyyz";
if (sameFreq(str)) {
    console.log("YES");
}
else {
    console.log("NO");
}

Output
NO

Time Complexity: O(n), where n is the size of the string
Auxiliary Space: O(26 + 26), extra space used by both the HashMaps.

Most Efficient & Simpler Solution:

This approach uses just 1 HashMap & makes 1 traversal on the input string and the HashMap.

Procedure:

  1. Populate the HashMap with the frequencies of each Character.
  2. Now iterate through this HashMap and find the maxFrequency, minFrequency, & count of occurrences of maxFrequency.
  3. Now using these 3 variables check if the given constraints of the problem are satisfied or not (as shown in the below mentioned code).
// Java program to check if frequency of all
// characters can become same by one removal
import java.util.HashMap;

public class Solution {
    private static boolean sameFreq(String s)
    {
        HashMap<Character, Integer> freqMap
            = new HashMap<>();

        // logic to populate the frequency of each
        // character.
        for (int i = 0; i < s.length(); i++) {
            freqMap.put(s.charAt(i),
                        freqMap.getOrDefault(s.charAt(i), 0)
                            + 1);
        }

        // Logic to find the maxFrequency, minFrequency,
        // & count of occurrences of maxFrequency.
        int maxFreqValue = Integer.MIN_VALUE;
        int minFreqValue = Integer.MAX_VALUE;
        int maxFreqCounter = 0;
        for (char key : freqMap.keySet()) {
            if (freqMap.get(key) == maxFreqValue) {
                maxFreqCounter++;
            }

            if (freqMap.get(key) > maxFreqValue) {
                maxFreqValue = freqMap.get(key);
                maxFreqCounter = 1;
            }

            if (freqMap.get(key) < minFreqValue) {
                minFreqValue = freqMap.get(key);
            }
        }

        // Now using those 3 variables check if the
        // given constraints of the problem are satisfied
        // or not.
        if ((maxFreqValue - minFreqValue) == 0) {
            return true;
        }
        else if ((maxFreqValue - minFreqValue) == 1) {
            if (maxFreqCounter == 1) {
                return true;
            }
            else {
                return false;
            }
        }
        else {
            return false;
        }
    }

    public static void main(String[] args)
    {

        // corner-case input when there exists multiple
        // occurrences of maxFrequency characters. In this
        // case, it is x and y which are having equal
        // frequencies and are maxFrequencies as well.
        String str = "xxxyyyzzaa";
        if (sameFreq(str)) {
            System.out.println("YES");
        }
        else {
            System.out.println("NO");
        }
    }
}
// This code is contributed by Nikhil B.
function sameFreq(s) {
    let freqMap = new Map();

    // logic to populate the frequency of each character.
    for (let i = 0; i < s.length; i++) {
        freqMap.set(s.charAt(i), (freqMap.get(s.charAt(i)) || 0) + 1);
    }

    // Logic to find the maxFrequency, minFrequency,
    // & count of occurrences of maxFrequency.
    let maxFreqValue = -Infinity;
    let minFreqValue = Infinity;
    let maxFreqCounter = 0;
    for (let [key, value] of freqMap) {
        if (value === maxFreqValue) {
            maxFreqCounter++;
        }

        if (value > maxFreqValue) {
            maxFreqValue = value;
            maxFreqCounter = 1;
        }

        if (value < minFreqValue) {
            minFreqValue = value;
        }
    }

    // Now using those 3 variables check if the
    // given constraints of the problem are satisfied or not.
    if ((maxFreqValue - minFreqValue) === 0) {
        return true;
    } else if ((maxFreqValue - minFreqValue) === 1) {
        if (maxFreqCounter === 1) {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

// Test case
let str = "xxxyyyzzaa";
if (sameFreq(str)) {
    console.log("YES");
} else {
    console.log("NO");
}

Output
NO

Time Complexity : O(n). Where, 'n' is the size of the input string.
Auxiliary Space : O(26). The HashMap can at max grow up to a size of 26. Hence, it's a constant space complexity solution.

Article Tags :