Given two strings s1 and s2, both containing the same set of characters in any order, except that one of the strings contains exactly one extra character, find and return the extra character. The characters may appear multiple times, and the order of characters in the strings is not necessarily the same.
Examples:
Input: s1 = "abba", s2 = "baxab"
Output: 'x'
Explanation: Both strings contain the characters a, b, b, and a. String s2 has one additional character x.
Input: s1 = "aaaa", s2 = "aaa"
Output: 'a'
Explanation: Both strings contain the character 'a', but s1 contains it four times while s2 contains it three times. Therefore, the extra character is 'a'.
Table of Content
[Naive Approach] Compare Character Frequencies - O(n * 26) Time and O(1) Space
The idea is to count the occurrences of every lowercase character separately in both strings. For each character from 'a' to 'z', count how many times it appears in s1 and s2 by scanning both strings. The character whose frequency differs is the extra character.
#include <bits/stdc++.h>
using namespace std;
char extraChar(string &s1, string &s2)
{
// Check every lowercase character.
for (char ch = 'a'; ch <= 'z'; ch++)
{
int cnt1 = 0, cnt2 = 0;
// Count occurrences in s1.
for (char c : s1)
{
if (c == ch)
cnt1++;
}
// Count occurrences in s2.
for (char c : s2)
{
if (c == ch)
cnt2++;
}
// Return the character whose frequency differs.
if (cnt1 != cnt2)
return ch;
}
return '\0';
}
int main()
{
string s1 = "aaaa";
string s2 = "aaa";
cout << "'" << extraChar(s1, s2) << "'";
return 0;
}
import java.util.*;
public class GFG {
public static char extraChar(String s1, String s2)
{
// Check every lowercase character.
for (char ch = 'a'; ch <= 'z'; ch++) {
int cnt1 = 0, cnt2 = 0;
// Count occurrences in s1.
for (char c : s1.toCharArray()) {
if (c == ch)
cnt1++;
}
// Count occurrences in s2.
for (char c : s2.toCharArray()) {
if (c == ch)
cnt2++;
}
// Return the character whose frequency differs.
if (cnt1 != cnt2)
return ch;
}
return '\0';
}
public static void main(String[] args)
{
String s1 = "aaaa";
String s2 = "aaa";
System.out.println("'" + extraChar(s1, s2) + "'");
}
}
def extraChar(s1, s2):
# Check every lowercase character.
for ch in range(ord('a'), ord('z') + 1):
ch = chr(ch)
cnt1 = s1.count(ch)
cnt2 = s2.count(ch)
# Return the character whose frequency differs.
if cnt1 != cnt2:
return ch
return '\0'
if __name__ == "__main__":
s1 = "aaaa"
s2 = "aaa"
print(f"'{extraChar(s1, s2)}'")
using System;
class GFG {
static char extraChar(string s1, string s2)
{
// Check every lowercase character.
for (char ch = 'a'; ch <= 'z'; ch++) {
int cnt1 = 0, cnt2 = 0;
// Count occurrences in s1.
foreach(char c in s1)
{
if (c == ch)
cnt1++;
}
// Count occurrences in s2.
foreach(char c in s2)
{
if (c == ch)
cnt2++;
}
// Return the character whose frequency differs.
if (cnt1 != cnt2)
return ch;
}
return '\0';
}
static void Main()
{
string s1 = "aaaa";
string s2 = "aaa";
Console.WriteLine("'" + extraChar(s1, s2) + "'");
}
}
function extraChar(s1, s2)
{
// Check every lowercase character.
for (let ch = "a".charCodeAt(0);
ch <= "z".charCodeAt(0); ch++) {
let cnt1 = 0, cnt2 = 0;
// Count occurrences in s1.
for (let c of s1) {
if (c === String.fromCharCode(ch))
cnt1++;
}
// Count occurrences in s2.
for (let c of s2) {
if (c === String.fromCharCode(ch))
cnt2++;
}
// Return the character whose frequency differs.
if (cnt1 !== cnt2)
return String.fromCharCode(ch);
}
return "\0";
}
// Driver Code
let s1 = "aaaa";
let s2 = "aaa";
console.log(`'${extraChar(s1, s2)}'`);
Output
'a'
[Better Approach] Single Frequency Array - O(n) Time and O(1) Space
The idea is to maintain a frequency array of size 26. First, increase the count for every character in one string and decrease the count for every character in the other string. Since one string contains exactly one extra character, only one frequency will become non-zero. That character is the required answer.
Working of Approach:
- Create a frequency array of size 26 to store the count of each lowercase character.
- Traverse the first string and increment the frequency of every character.
- Traverse the second string and decrement the frequency of every character.
- Since both strings differ by exactly one extra character, only its frequency remains non-zero after both traversals.
- Finally, scan the frequency array and return the character whose frequency is non-zero.
#include <bits/stdc++.h>
using namespace std;
char extraChar(string &s1, string &s2)
{
// Frequency array for lowercase letters.
int freq[26] = {0};
// Add frequencies of characters in s1.
for (char ch : s1)
freq[ch - 'a']++;
// Remove frequencies of characters in s2.
for (char ch : s2)
freq[ch - 'a']--;
// Find the character whose frequency is non-zero.
for (int i = 0; i < 26; i++)
{
if (freq[i] != 0)
return char(i + 'a');
}
return '\0';
}
int main()
{
string s1 = "aaaa";
string s2 = "aaa";
cout << "'" << extraChar(s1, s2) << "'";
return 0;
}
import java.util.*;
class GFG {
static char extraChar(String s1, String s2)
{
// Frequency array for lowercase letters.
int[] freq = new int[26];
// Add frequencies of characters in s1.
for (char ch : s1.toCharArray())
freq[ch - 'a']++;
// Remove frequencies of characters in s2.
for (char ch : s2.toCharArray())
freq[ch - 'a']--;
// Find the character whose frequency is non-zero.
for (int i = 0; i < 26; i++) {
if (freq[i] != 0)
return (char)(i + 'a');
}
return '\0';
}
public static void main(String[] args)
{
String s1 = "aaaa";
String s2 = "aaa";
System.out.print("'" + extraChar(s1, s2) + "'");
}
}
def extraChar(s1, s2):
# Frequency array for lowercase letters.
freq = [0] * 26
# Add frequencies of characters in s1.
for ch in s1:
freq[ord(ch) - ord('a')] += 1
# Remove frequencies of characters in s2.
for ch in s2:
freq[ord(ch) - ord('a')] -= 1
# Find the character whose frequency is non-zero.
for i in range(26):
if freq[i] != 0:
return chr(i + ord('a'))
return '\0'
if __name__ == "__main__":
s1 = "aaaa"
s2 = "aaa"
print(f"'{extraChar(s1, s2)}'")
using System;
class GFG {
static char extraChar(string s1, string s2)
{
// Frequency array for lowercase letters.
int[] freq = new int[26];
// Add frequencies of characters in s1.
foreach(char ch in s1) freq[ch - 'a']++;
// Remove frequencies of characters in s2.
foreach(char ch in s2) freq[ch - 'a']--;
// Find the character whose frequency is non-zero.
for (int i = 0; i < 26; i++) {
if (freq[i] != 0)
return (char)(i + 'a');
}
return '\0';
}
static void Main()
{
string s1 = "aaaa";
string s2 = "aaa";
Console.Write("'" + extraChar(s1, s2) + "'");
}
}
function extraChar(s1, s2)
{
// Frequency array for lowercase letters.
let freq = new Array(26).fill(0);
// Add frequencies of characters in s1.
for (let ch of s1) {
freq[ch.charCodeAt(0) - "a".charCodeAt(0)]++;
}
// Remove frequencies of characters in s2.
for (let ch of s2) {
freq[ch.charCodeAt(0) - "a".charCodeAt(0)]--;
}
// Find the character whose frequency is non-zero.
for (let i = 0; i < 26; i++) {
if (freq[i] != 0) {
return String.fromCharCode(i
+ "a".charCodeAt(0));
}
}
return "\0";
}
// Driver Code
let s1 = "aaaa";
let s2 = "aaa";
console.log(`'${extraChar(s1, s2)}'`);
Output
'a'
[Expected Approach] Using Bitwise XOR - O(n) Time and O(1) Space
The idea is to XOR all the characters from both strings. Since XOR of a number with itself is 0 (x ^ x = 0) and XOR with 0 leaves the number unchanged (x ^ 0 = x), every matching character from the two strings cancels out. As one string contains exactly one extra character, only that character remains after all XOR operations.
Working of Approach:
- XOR all characters of both strings one by one using a single variable ans.
- Characters present in both strings cancel each other out because x ^ x = 0.
- The only value left after all XOR operations is the extra character, which is returned.
Let us understand with an example:
Input: s1 = "aaaa", s2 = "aaa"
- Initialize ans = 0 and XOR all characters of s1 = "aaaa". Since 'a' is XORed four times, the value becomes 0.
- Next, XOR all characters of s2 = "aaa". After XORing three 'a' characters, ans becomes 'a'.
- Every matching character from the two strings cancels out because x ^ x = 0.
- Only the extra occurrence of 'a' remains after all XOR operations.
- Hence, the function returns 'a'.
#include <bits/stdc++.h>
using namespace std;
char extraChar(string &s1, string &s2)
{
char ans = 0;
// XOR all characters of the first string.
for (char ch : s1)
{
ans ^= ch;
}
// XOR all characters of the second string.
for (char ch : s2)
{
ans ^= ch;
}
// Matching characters cancel out,
// leaving only the extra character.
return ans;
}
int main()
{
string s1 = "aaaa";
string s2 = "aaa";
cout << "'" << extraChar(s1, s2) << "'";
return 0;
}
import java.util.*;
public class GFG {
public static char extraChar(String s1, String s2)
{
char ans = 0;
// XOR all characters of the first string.
for (char ch : s1.toCharArray()) {
ans ^= ch;
}
// XOR all characters of the second string.
for (char ch : s2.toCharArray()) {
ans ^= ch;
}
// Matching characters cancel out,
// leaving only the extra character.
return ans;
}
public static void main(String[] args)
{
String s1 = "aaaa";
String s2 = "aaa";
System.out.println("'" + extraChar(s1, s2) + "'");
}
}
def extraChar(s1, s2):
ans = 0
# XOR all characters of the first string.
for ch in s1:
ans ^= ord(ch)
# XOR all characters of the second string.
for ch in s2:
ans ^= ord(ch)
# Matching characters cancel out,
# leaving only the extra character.
return chr(ans)
if __name__ == '__main__':
s1 = "aaaa"
s2 = "aaa"
print(f"'{extraChar(s1, s2)}'")
using System;
public class GFG {
public static char extraChar(string s1, string s2)
{
char ans = (char)0;
// XOR all characters of the first string.
foreach(char ch in s1) { ans = (char)(ans ^ ch); }
// XOR all characters of the second string.
foreach(char ch in s2) { ans = (char)(ans ^ ch); }
// Matching characters cancel out,
// leaving only the extra character.
return ans;
}
public static void Main()
{
string s1 = "aaaa";
string s2 = "aaa";
Console.WriteLine("'" + extraChar(s1, s2) + "'");
}
}
function extraChar(s1, s2)
{
let ans = 0;
// XOR all characters of the first string.
for (let ch of s1) {
ans ^= ch.charCodeAt(0);
}
// XOR all characters of the second string.
for (let ch of s2) {
ans ^= ch.charCodeAt(0);
}
// Matching characters cancel out,
// leaving only the extra character.
return String.fromCharCode(ans);
}
// Driver Code
const s1 = "aaaa";
const s2 = "aaa";
console.log(`'${extraChar(s1, s2)}'`);
Output
'a'