Open In App

Balance the occurrence of unique characters

Last Updated : 20 Apr, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given two strings, word1, and word2, where each string has a 0-based index. A move is defined as selecting two indices, i and j, such that 0 ? i < word1.length and 0 ? j < word2.length, and exchanging the characters at these indices in word1 and word2. Determine if it is possible to make exactly one move to make the number of unique characters in both word1 and word2 equal. Return true if it is possible, and false otherwise.

Examples:

Input: word1 = “cdefg”, word2 = “hijkl”
Output: true
Explanation: Both resulting strings will have 5 distinct characters, regardless of which indices we swap.

Input: word1 = “fh”, word2 = “b”
Output: false
Explanation: Any pair of swaps would yield two distinct characters in the first string, and one in the second string.

Approach: To solve the problem follow the below idea/intuition:

Since we can choose any indices from both strings to swap and at the end we just need both to have the same number of distinct characters. The only thing that matters is which alphabet (‘a’, ‘b’, ‘c’, …) we choose from word1 and which alphabet (‘a’, ‘b’, ‘c’, …) we choose from word2 to swap. Since, only lowercase(26 alphabets) are there. We can try swapping all possible alphabet pairs between the two.

Follow the below steps to solve the problem:

  •   Create two maps to store the frequency of characters in each word.
  •   Loop through each possible pair of characters, c1, and c2, from ‘a’ to ‘z’.
  •   If c1 is found in word1 and c2 is found in word2, remove c1 from word1’s map and add c2, and remove c2 from word2’s map and add c1.
  •  Check if the sizes of the maps are equal. If they are, it means that both words now have the same number of distinct characters and the result is true.
  •  If the map sizes are not equal, put back c1 in word1’s map and c2 in word2’s map to reset the maps.

In short, the procedure involves swapping pairs of characters in the words, checking if the number of distinct characters remains the same and if not, resetting the words to their original state.

Below is the implementation for the above approach:

C++




// Cpp code for the above approach
#include <bits/stdc++.h>
using namespace std;
 
void insertAndRemove(unordered_map<char, int>& mp,
                     char toInsert, char toRemove)
{
 
    // Made this helper fn for easy
    // insert/ removal from map
 
    // Increment freq for char
    // to be inserted
    mp[toInsert]++;
 
    // Decrement freq for char
    // to be removed
    mp[toRemove]--;
    if (mp[toRemove] == 0)
 
        // If freq of that
        // char reaches zero,
        mp.erase(toRemove);
 
    // Then remove the key
    // from map
}
 
bool balanceOccurrences(string word1, string word2)
{
    unordered_map<char, int> mp1, mp2;
 
    // Store freq of chars in
    // word1 in mp1
    for (char w1 : word1)
        mp1[w1]++;
 
    // Store freq of chars in
    // word2 in mp2
    for (char w2 : word2)
        mp2[w2]++;
 
    for (char c1 = 'a'; c1 <= 'z'; c1++) {
        for (char c2 = 'a'; c2 <= 'z'; c2++) {
            if (mp1.count(c1) == 0 || mp2.count(c2) == 0)
 
                // If any of the char
                // is not present
                // then skip
                continue;
 
            insertAndRemove(mp1, c2, c1);
 
            // Insert c2 to word1 and
            // remove c1 from word1
            insertAndRemove(mp2, c1, c2);
            // Insert c1 to word2 and
            // remove c2 from word2
 
            if (mp1.size() == mp2.size())
                return true;
 
            // If size of both maps are
            // equal then possible
            // return true
 
            // Reset back the maps
            insertAndRemove(mp1, c1, c2);
 
            // Insert c1 back to word1
            // and remove c2 from word1
            insertAndRemove(mp2, c2, c1);
 
            // Insert c2 back to word2
            // and remove c1 from word2
        }
    }
 
    return false;
}
 
// Drivers code
int main()
{
 
    string word1 = "cdefg";
    string word2 = "hijkl";
 
    // Function Call
    if (balanceOccurrences(word1, word2))
        cout << "True";
    else
        cout << "False";
    return 0;
}


Java




// Java code for the above approach
import java.util.*;
 
public class Main {
 
    static void insertAndRemove(Map<Character, Integer> mp,
                                char toInsert,
                                char toRemove)
    {
 
        // Made this helper function for easy
        // insert/ removal from map
 
        // Increment freq for char
        // to be inserted
        mp.put(toInsert, mp.getOrDefault(toInsert, 0) + 1);
 
        // Decrement freq for char
        // to be removed
        mp.put(toRemove, mp.getOrDefault(toRemove, 0) - 1);
        if (mp.get(toRemove) == 0)
 
            // If freq of that
            // char reaches zero,
            mp.remove(toRemove);
 
        // Then remove the key
        // from map
    }
 
    static boolean balanceOccurrences(String word1,
                                     String word2)
    {
        Map<Character, Integer> mp1 = new HashMap<>();
        Map<Character, Integer> mp2 = new HashMap<>();
 
        // Store freq of chars in
        // word1 in mp1
        for (char w1 : word1.toCharArray())
            mp1.put(w1, mp1.getOrDefault(w1, 0) + 1);
 
        // Store freq of chars in
        // word2 in mp2
        for (char w2 : word2.toCharArray())
            mp2.put(w2, mp2.getOrDefault(w2, 0) + 1);
 
        for (char c1 = 'a'; c1 <= 'z'; c1++) {
            for (char c2 = 'a'; c2 <= 'z'; c2++) {
                if (!mp1.containsKey(c1)
                    || !mp2.containsKey(c2))
 
                    // If any of the char
                    // is not present
                    // then skip
                    continue;
 
                insertAndRemove(mp1, c2, c1);
 
                // Insert c2 to word1 and
                // remove c1 from word1
                insertAndRemove(mp2, c1, c2);
                // Insert c1 to word2 and
                // remove c2 from word2
 
                if (mp1.size() == mp2.size())
                    return true;
 
                // If size of both maps are
                // equal then possible
                // return true
 
                // Reset back the maps
                insertAndRemove(mp1, c1, c2);
 
                // Insert c1 back to word1
                // and remove c2 from word1
                insertAndRemove(mp2, c2, c1);
 
                // Insert c2 back to word2
                // and remove c1 from word2
            }
        }
 
        return false;
    }
 
    // Drivers code
    public static void main(String[] args)
    {
 
        String word1 = "cdefg";
        String word2 = "hijkl";
 
        // Function Call
        if (balanceOccurrences(word1, word2))
            System.out.println("True");
        else
            System.out.println("False");
    }
}


Python3




# Python code for the above approach
 
def insertAndRemove(mp, toInsert, toRemove):
     
    # Made this helper fn for easy
    # insert/ removal from map
 
    # Increment freq for char
    # to be inserted
    mp[toInsert] = mp.get(toInsert, 0) + 1
     
    # Decrement freq for char
    # to be removed
    if toRemove in mp:
        mp[toRemove] -= 1
         
        # If freq of that
        # char reaches zero,
        if mp[toRemove] == 0:
             
            # Then remove the key
            # from map
            del mp[toRemove]
 
def balanceOccurrences(word1, word2):
    mp1, mp2 = {}, {}
     
    # Store freq of chars in
    # word1 in mp1
    for w1 in word1:
        mp1[w1] = mp1.get(w1, 0) + 1
         
    # Store freq of chars in
    # word2 in mp2
    for w2 in word2:
        mp2[w2] = mp2.get(w2, 0) + 1
 
    for c1 in 'abcdefghijklmnopqrstuvwxyz':
        for c2 in 'abcdefghijklmnopqrstuvwxyz':
            if c1 not in mp1 or c2 not in mp2:
                 
                # If any of the char
                # is not present
                # then skip
                continue
             
            # Insert c2 to word1 and
            # remove c1 from word1
            insertAndRemove(mp1, c2, c1)
             
            # Insert c1 to word2 and
            # remove c2 from word2
            insertAndRemove(mp2, c1, c2)
 
            # If size of both maps are
            # equal then possible
            # return true
            if len(mp1) == len(mp2):
                return True
 
            # Insert c1 back to word1
            # and remove c2 from word1
            insertAndRemove(mp1, c1, c2)
             
            # Insert c2 back to word2
            # and remove c1 from word2
            insertAndRemove(mp2, c2, c1)
 
    return False
 
# Drivers code
word1 = "cdefg"
word2 = "hijkl"
 
# Function Call
if balanceOccurrences(word1, word2):
    print("True")
else:
    print("False")
 
# This code is contributed by Prasad Kandekar(prasad264)


C#




// C# code for the above approach
 
using System;
using System.Collections.Generic;
 
class GFG
{
    static void InsertAndRemove(Dictionary<char, int> mp, char toInsert, char toRemove)
    {
        // Made this helper method for easy
        // insert/ removal from dictionary
 
        // Increment freq for char
        // to be inserted
        if (mp.ContainsKey(toInsert))
        {
            mp[toInsert]++;
        }
        else
        {
            mp[toInsert] = 1;
        }
 
        // Decrement freq for char
        // to be removed
        mp[toRemove]--;
        if (mp[toRemove] == 0)
        {
            // If freq of that
            // char reaches zero,
            mp.Remove(toRemove);
        }
    }
 
    static bool BalanceOccurrences(string word1, string word2)
    {
        Dictionary<char, int> mp1 = new Dictionary<char, int>();
        Dictionary<char, int> mp2 = new Dictionary<char, int>();
 
        // Store freq of chars in
        // word1 in mp1
        foreach (char w1 in word1)
        {
            if (mp1.ContainsKey(w1))
            {
                mp1[w1]++;
            }
            else
            {
                mp1[w1] = 1;
            }
        }
 
        // Store freq of chars in
        // word2 in mp2
        foreach (char w2 in word2)
        {
            if (mp2.ContainsKey(w2))
            {
                mp2[w2]++;
            }
            else
            {
                mp2[w2] = 1;
            }
        }
 
        for (char c1 = 'a'; c1 <= 'z'; c1++)
        {
            for (char c2 = 'a'; c2 <= 'z'; c2++)
            {
                if (!mp1.ContainsKey(c1) || !mp2.ContainsKey(c2))
                {
                    // If any of the char
                    // is not present
                    // then skip
                    continue;
                }
 
                InsertAndRemove(mp1, c2, c1);
                // Insert c2 to word1 and
                // remove c1 from word1
                InsertAndRemove(mp2, c1, c2);
                // Insert c1 to word2 and
                // remove c2 from word2
 
                if (mp1.Count == mp2.Count)
                {
                    return true;
                }
 
                // If size of both dictionaries are
                // equal then possible
                // return true
 
                // Reset back the dictionaries
                InsertAndRemove(mp1, c1, c2);
                // Insert c1 back to word1
                // and remove c2 from word1
                InsertAndRemove(mp2, c2, c1);
                // Insert c2 back to word2
                // and remove c1 from word2
            }
        }
 
        return false;
    }
 
    // Drivers code
    static void Main()
    {
        string word1 = "cdefg";
        string word2 = "hijkl";
 
        // Function Call
        if (BalanceOccurrences(word1, word2))
        {
            Console.WriteLine("True");
        }
        else
        {
            Console.WriteLine("False");
        }
    }
}
 
//this code is contributed by bhardwajji


Javascript




function insertAndRemove(mp, toInsert, toRemove) {
  // Increment freq for char to be inserted
  mp[toInsert] = (mp[toInsert] || 0) + 1;
 
  // Decrement freq for char to be removed
  mp[toRemove] = (mp[toRemove] || 0) - 1;
  if (mp[toRemove] === 0) {
    // If freq of that char reaches zero, then remove the key from map
    delete mp[toRemove];
  }
}
 
function balanceOccurrences(word1, word2) {
  const mp1 = {}, mp2 = {};
 
  // Store freq of chars in word1 in mp1
  for (const w1 of word1) {
    mp1[w1] = (mp1[w1] || 0) + 1;
  }
 
  // Store freq of chars in word2 in mp2
  for (const w2 of word2) {
    mp2[w2] = (mp2[w2] || 0) + 1;
  }
 
  for (let c1 = 'a'.charCodeAt(); c1 <= 'z'.charCodeAt(); c1++) {
    for (let c2 = 'a'.charCodeAt(); c2 <= 'z'.charCodeAt(); c2++) {
      const char1 = String.fromCharCode(c1), char2 = String.fromCharCode(c2);
      if (!mp1[char1] || !mp2[char2]) {
        // If any of the char is not present then skip
        continue;
      }
 
      insertAndRemove(mp1, char2, char1);
      // Insert char2 to word1 and remove char1 from word1
      insertAndRemove(mp2, char1, char2);
      // Insert char1 to word2 and remove char2 from word2
 
      if (Object.keys(mp1).length === Object.keys(mp2).length) {
        // If size of both maps are equal then possible, return true
        return true;
      }
 
      // Reset back the maps
      insertAndRemove(mp1, char1, char2);
      // Insert char1 back to word1 and remove char2 from word1
      insertAndRemove(mp2, char2, char1);
      // Insert char2 back to word2 and remove char1 from word2
    }
  }
 
  return false;
}
 
// Drivers code
const word1 = "cdefg";
const word2 = "hijkl";
 
// Function Call
if (balanceOccurrences(word1, word2)) {
  console.log("True");
} else {
  console.log("False");
}


Output

True

Time Complexity:   O(N+M+26*26) i.e. O(N+M): where N is the size of word1 and M is the size of word2. We iterated both strings once, and a fixed 26*26 for loop (This 26*26 is constant, and doesn’t depend on input variables i.e. string sizes N or M)
Auxiliary Space:  O(26) i.e O(1): Since word1 and word2 consist of only lowercase English letters, so both map can have 26 elements only at max



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads