Unique Number III
Given an array where every element occurs three times, except one element which occurs only once. Find the element that occurs once.
Examples:
Input: arr[] = [1, 10, 1, 1]
Output: 10
Explanation: 10 occurs once in the array while the other element 1 occurs thrice.Input: arr[] = [3, 2, 1, 34, 34, 1, 2, 34, 2, 1]
Output: 3
Explanation: All elements except 3 occurs thrice in the array.
Table of Content
- [Naive Approach] Nested Loop Frequency Counting - O(n^2) Time and O(1) Space
- [Better Approach 1] Count Frequency of Elements Using Map - O(n) Time and O(n) Space
- [Better Approach 2] Using Math - O(n) Time and O(n) Space
- [Expected Approach 1] Using Bit Manipulation - O(n) Time and O(1) Space
- [Expected Approach 2] Using Bitmask - O(n) Time and O(1) Space
[Naive Approach] Nested Loop Frequency Counting - O(n^2) Time and O(1) Space
This approach iterates through the array and counts the frequency of each element using a nested loop. For each element, the inner loop counts how many times it appears in the array. If an element appears exactly once, it is returned as the result. This method ensures that the correct element is identified but is inefficient due to the nested loop.
#include <iostream>
#include <vector>
using namespace std;
int getSingle(vector<int>& arr) {
int n = arr.size();
// Iterate over every element
for (int i = 0; i < n; i++) {
// Initialize count to 0
int count = 0;
for (int j = 0; j < n; j++) {
// Count the frequency of the element
if (arr[i] == arr[j]) {
count++;
}
}
// If the frequency of the element is one
if (count == 1) {
return arr[i];
}
}
// If no element exists at most once
return -1;
}
int main() {
vector<int> arr = {1, 10, 1, 1};
cout << getSingle(arr) << endl;
return 0;
}
import java.util.*;
class GfG {
static int getSingle(int[] arr) {
int n = arr.length;
// Iterate over every element
for (int i = 0; i < n; i++) {
// Initialize count to 0
int count = 0;
for (int j = 0; j < n; j++) {
// Count the frequency of the element
if (arr[i] == arr[j]) {
count++;
}
}
// If the frequency of the element is one
if (count == 1) {
return arr[i];
}
}
// If no element exists at most once
return -1;
}
public static void main(String[] args) {
int[] arr = {1, 10, 1, 1};
System.out.println(getSingle(arr));
}
}
def getSingle(arr):
n = len(arr)
# Iterate over every element
for i in range(n):
# Initialize count to 0
count = 0
for j in range(n):
# Count the frequency of the element
if arr[i] == arr[j]:
count += 1
# If the frequency of the element is one
if count == 1:
return arr[i]
# If no element exists at most once
return -1
if __name__ == "__main__":
arr = [1, 10, 1, 1]
print(getSingle(arr))
using System;
class GfG {
static int getSingle(int[] arr) {
int n = arr.Length;
// Iterate over every element
for (int i = 0; i < n; i++) {
// Initialize count to 0
int count = 0;
for (int j = 0; j < n; j++) {
// Count the frequency of the element
if (arr[i] == arr[j]) {
count++;
}
}
// If the frequency of the element is one
if (count == 1) {
return arr[i];
}
}
// If no element exists at most once
return -1;
}
static void Main(string[] args) {
int[] arr = {1, 10, 1, 1};
Console.WriteLine(getSingle(arr));
}
}
function getSingle(arr) {
let n = arr.length;
// Iterate over every element
for (let i = 0; i < n; i++) {
// Initialize count to 0
let count = 0;
for (let j = 0; j < n; j++) {
// Count the frequency of the element
if (arr[i] === arr[j]) {
count++;
}
}
// If the frequency of the element is one
if (count === 1) {
return arr[i];
}
}
// If no element exists at most once
return -1;
}
let arr = [1, 10, 1, 1];
console.log(getSingle(arr));
Output
10
[Better Approach 1] Count Frequency of Elements Using Map - O(n) Time and O(n) Space
Use a map or dictionary to count the frequency of each element in the array. Then, iterate through the map and return the element whose frequency is exactly one.
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
// Function to find the element that appears only once
int getSingle(vector<int>& arr) {
// To store frequency of each element
unordered_map<int, int> freq;
// Count the frequency of each number in the array
for (int num : arr) {
freq[num]++;
}
// Find the number that occurs only once
for (auto it : freq) {
if (it.second == 1)
return it.first;
}
// Return 0 if no unique element is found
return 0;
}
int main() {
vector<int> arr = {1, 10, 1, 1};
// Output the single occurrence element
cout << getSingle(arr) << endl;
return 0;
}
import java.util.ArrayList;
import java.util.HashMap;
public class GfG{
// Function to find the element that appears only once
public static int getSingle(int [] arr) {
HashMap<Integer, Integer> mp = new HashMap<>();
// Count frequency of each element
for (int it : arr) {
mp.put(it, mp.getOrDefault(it, 0) + 1);
}
// Return the element that appears only once
for (var it : mp.entrySet()) {
if (it.getValue() == 1) {
return it.getKey();
}
}
return 0;
}
public static void main(String[] args) {
int [] arr = {1, 10, 1, 1};
System.out.println(getSingle(arr));
}
}
def getSingle(arr):
mp = {}
# Count frequency of each element
for it in arr:
if it in mp:
mp[it] += 1
else:
mp[it] = 1
# Return the element that appears only once
for key in mp:
if mp[key] == 1:
return key
return 0
if __name__ == "__main__":
arr = [1, 10, 1, 1]
print(getSingle(arr))
using System;
using System.Collections.Generic;
class GfG
{
// Function to find the element that appears only once
public static int getSingle(int [] arr)
{
Dictionary<int, int> mp = new Dictionary<int, int>();
// Count frequency of each element
foreach (int it in arr)
{
if (mp.ContainsKey(it))
mp[it]++;
else
mp[it] = 1;
}
// Return the element that appears only once
foreach (var it in mp)
{
if (it.Value == 1)
return it.Key;
}
return 0;
}
public static void Main()
{
int [] arr = { 1, 10, 1, 1 };
Console.WriteLine(getSingle(arr));
}
}
function getSingle(arr) {
const mp = new Map();
// Count frequency of each element
for (const it of arr) {
mp.set(it, (mp.get(it) || 0) + 1);
}
// Return the element that appears only once
for (const [key, value] of mp.entries()) {
if (value === 1) {
return key;
}
}
return 0;
}
// Example usage
const arr = [1, 10, 1, 1];
console.log(getSingle(arr));
Output
10
[Better Approach 2] Using Math - O(n) Time and O(n) Space
This approach works by leveraging a clever mathematical trick involving the sum of all elements and the sum of unique elements. In the given problem, every element appears exactly three times except one, which appears only once. By summing all elements in the array (
totalSum
) and also summing only the unique elements using a set (uniqueSum
), we notice that if all elements appeared three times, then3 *
uniqueSum
would equaltotalSum
. However, since one element appears only once, the difference3 * uniqueSum - totalSum
equals twice the unique element. Dividing this result by 2 gives us the value of the single-occurring element.
This method is efficient and avoids complex logic, working perfectly under the assumption that all other elements appear exactly three times.
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
int getSingle(vector<int>& arr) {
unordered_set<int> uniqueElements;
int totalSum = 0;
// Calculate the sum of all elements and collect unique ones
for (int num : arr) {
totalSum += num;
uniqueElements.insert(num);
}
int uniqueSum = 0;
// Sum of all unique elements
for (int num : uniqueElements) {
uniqueSum += num;
}
// 3 * (sum of unique elements) - (sum of all elements)
// gives twice the unique element that appears once.
// So we divide by 2 to get the actual element.
int result = (3 * uniqueSum - totalSum) / 2;
return result;
}
int main() {
vector<int> arr = {1, 10, 1, 1};
// Output the single occurrence element
cout << getSingle(arr) << endl;
return 0;
}
import java.util.HashSet;
public class Main {
public static int getSingle(int[] arr) {
HashSet<Integer> uniqueElements = new HashSet<>();
int totalSum = 0;
// Calculate the sum of all elements and collect unique ones
for (int num : arr) {
totalSum += num;
uniqueElements.add(num);
}
int uniqueSum = 0;
// Sum of all unique elements
for (int num : uniqueElements) {
uniqueSum += num;
}
// 3 * (sum of unique elements) - (sum of all elements) = 2 * unique one
return (3 * uniqueSum - totalSum) / 2;
}
public static void main(String[] args) {
int[] arr = {1, 10, 1, 1};
// Output the single occurrence element
System.out.println(getSingle(arr));
}
}
def getSingle(arr):
unique_elements = set()
total_sum = 0
# Calculate total sum and collect unique elements
for num in arr:
total_sum += num
unique_elements.add(num)
unique_sum = sum(unique_elements)
# 3 * (sum of unique elements) - (sum of all elements) = 2 * unique one
result = (3 * unique_sum - total_sum) // 2
return result
# Driver code
if __name__ == "__main__":
arr = [1, 10, 1, 1]
print(getSingle(arr))
using System;
using System.Collections.Generic;
class Program
{
public static int GetSingle(int[] arr)
{
HashSet<int> uniqueElements = new HashSet<int>();
int totalSum = 0;
// Calculate total sum and collect unique elements
foreach (int num in arr)
{
totalSum += num;
uniqueElements.Add(num);
}
int uniqueSum = 0;
// Sum of all unique elements
foreach (int num in uniqueElements)
{
uniqueSum += num;
}
// 3 * (sum of unique elements) - (sum of all elements) = 2 * unique one
return (3 * uniqueSum - totalSum) / 2;
}
static void Main()
{
int[] arr = { 1, 10, 1, 1 };
// Output the single occurrence element
Console.WriteLine(GetSingle(arr));
}
}
function getSingle(arr) {
const uniqueElements = new Set();
let totalSum = 0;
// Calculate total sum and collect unique elements
for (let num of arr) {
totalSum += num;
uniqueElements.add(num);
}
let uniqueSum = 0;
for (let num of uniqueElements) {
uniqueSum += num;
}
// 3 * (sum of unique elements) - (sum of all elements) = 2 * unique one
return (3 * uniqueSum - totalSum) / 2;
}
// Driver code
let arr = [1, 10, 1, 1];
console.log(getSingle(arr));
Output
10
[Expected Approach 1] Using Bit Manipulation - O(n) Time and O(1) Space
The approach is based on the observation that in a binary representation of numbers, the bits that are set to 1 in the number that occurs only once will have a sum that is not a multiple of 3, while the bits that are set to 1 in the numbers that occur three times will have a sum that is a multiple of 3.
Here's a breakdown of the intuition:
- Counting set bits: For each bit position (from least significant to most significant), iterate through the array and count the number of times the bit is set to 1 in each element. This gives us the sum of set bits for that particular position across all elements.
- Modulo 3: Take the modulo 3 of the sum of set bits for each position. If the result is not 0, it means that the number that occurs only once has a 1 in that bit position, while the numbers that occur three times contribute in multiples of 3 and hence cancel out. For example, in the array
{1, 1, 1, 10}
, the binary representation is:1 = 0001
and10 = 1010
. Counting set bits at each position: bit 0 appears 3 times →3 % 3 = 0
, bit 1 appears once →1 % 3 = 1
, bit 2 →0 % 3 = 0
, bit 3 appears once →1 % 3 = 1
. So the final binary result is1010
, which is10
, the unique number.
Note: this approach won't work for negative numbers
#include <iostream>
#include <vector>
using namespace std;
int getSingle(vector<int>& arr) {
int result = 0, x, sum;
// Iterate through every bit (from 0 to 31)
for (int i = 0; i < 32; i++) {
sum = 0;
// Get the mask for the i-th bit position
x = (1 << i);
// Iterate over the array and count the number of set
// bits at position i
for (int j = 0; j < arr.size(); j++) {
// Check if the i-th bit is set in arr[j]
if (arr[j] & x) {
sum++;
}
}
// If sum is not a multiple of 3, it's part of the unique element
if ((sum % 3) != 0) {
result |= x;
}
}
return result;
}
int main() {
vector<int> arr = {1, 10, 1, 1};
cout << getSingle(arr) << endl;
return 0;
}
public class GfG {
public static int getSingle(int[] arr) {
int result = 0, x, sum;
// Iterate through every bit (from 0 to 31)
for (int i = 0; i < 32; i++) {
sum = 0;
x = (1 << i); // Mask for the i-th bit
// Count how many numbers have the i-th bit set
for (int j = 0; j < arr.length; j++) {
if ((arr[j] & x) != 0) {
sum++;
}
}
// If sum is not a multiple of 3, that bit belongs
// to the unique number
if ((sum % 3) != 0) {
result |= x;
}
}
return result;
}
public static void main(String[] args) {
int[] arr = {1, 10, 1, 1};
System.out.println(getSingle(arr));
}
}
def getSingle(arr):
result = 0
# Iterate through every bit (from 0 to 31)
for i in range(32):
sum = 0
# Get the mask for the i-th bit position
x = (1 << i)
# Iterate over the array and count the number of set bits
# at position i
for j in arr:
# Check if the i-th bit is set in j
if j & x:
sum += 1
# If sum is not a multiple of 3, it's part of the unique element
if sum % 3 != 0:
result |= x
return result
arr = [1, 10, 1, 1]
print(getSingle(arr))
using System;
using System.Collections.Generic;
class GfG {
static int getSingle(int [] arr) {
int result = 0, x, sum;
// Iterate through every bit (from 0 to 31)
for (int i = 0; i < 32; i++) {
sum = 0;
// Get the mask for the i-th bit position
x = (1 << i);
// Iterate over the array and count the number of set bits
// at position i
foreach (int j in arr) {
// Check if the i-th bit is set in j
if ((j & x) != 0) {
sum++;
}
}
// If sum is not a multiple of 3, it's part of the unique element
if (sum % 3 != 0) {
result |= x;
}
}
return result;
}
static void Main() {
int [] arr = { 1, 10, 1, 1 };
Console.WriteLine(getSingle(arr));
}
}
function getSingle(arr) {
let result = 0;
// Iterate through every bit (from 0 to 31)
for (let i = 0; i < 32; i++) {
let sum = 0;
// Get the mask for the i-th bit position
let x = (1 << i);
// Iterate over the array and count the number of set
// bits at position i
for (let j = 0; j < arr.length; j++) {
// Check if the i-th bit is set in arr[j]
if (arr[j] & x) {
sum++;
}
}
// If sum is not a multiple of 3, it's part of the unique element
if (sum % 3 !== 0) {
result |= x;
}
}
return result;
}
const arr = [1, 10, 1, 1];
console.log(getSingle(arr));
Output
10
[Expected Approach 2] Using Bitmask - O(n) Time and O(1) Space
Use two variables,
ones
andtwos
, to track the bits that appear an odd and even number of times, respectively. In each iteration, XOR the current element withones
to updateones
with the bits that occur an odd number of times. Then, use a bitwise AND betweenones
and the current element to identify the common bits that appear exactly three times. These common bits are then removed from bothones
andtwos
using a bitwise AND with the negation of the common bits. After all iterations,ones
will hold the element that appears only once.
Step by step Implementation:
- Initialize two integers
ones
andtwos
to track bits seen once and twice. - Iterate over each number in the array.
- Update
twos
with bits that are set in bothones
and the current number (twos |= ones & num
). - Update
ones
using XOR with the current number (ones ^= num
) to toggle bits based on odd occurrences. - Compute a mask by negating the common bits in
ones
andtwos
(mask = ~(ones & twos)
). - Apply the mask to both
ones
andtwos
to remove bits that have appeared three times. - After the loop,
ones
holds the bits of the number that appeared exactly once.
#include <iostream>
#include <vector>
using namespace std;
int getSingle(vector<int>& arr) {
int ones = 0, twos = 0, mask;
for (int num : arr) {
// Update 'twos' with bits that are set in both 'ones' and
// current number. These are bits that have appeared twice so far.
twos |= ones & num;
// XOR current number with 'ones' to add bits appearing
// odd number of times.If a bit has appeared once, it is set
// if it's the second time, it gets unset.
ones ^= num;
// (ones & twos) gives bits that are set in both, meaning they
// have now appeared 3 times. ~(ones & twos) inverts it to create
// a mask where those bits are 0 (to be cleared), and others are 1.
// Applying this mask on 'ones' and 'twos' removes the
// bits that have appeared three times.
mask = ~(ones & twos);
// Apply mask to keep only valid bits that haven't appeared 3 times.
ones &= mask;
twos &= mask;
}
return ones;
}
int main() {
vector<int> arr = {1, 10, 1, 1};
cout << getSingle(arr) << endl;
return 0;
}
import java.util.List;
import java.util.ArrayList;
class GfG {
public static int getSingle(int [] arr) {
int ones = 0, twos = 0, mask;
for (int num : arr) {
// Update 'twos' with bits that are set in both 'ones' and
// current number. These are bits that have appeared twice so far.
twos |= ones & num;
// XOR current number with 'ones' to add bits appearing
// odd number of times.If a bit has appeared once, it is set
// if it's the second time, it gets unset.
ones ^= num;
// (ones & twos) gives bits that are set in both, meaning they
// have now appeared 3 times. ~(ones & twos) inverts it to create
// a mask where those bits are 0 (to be cleared), and others are 1.
// Applying this mask on 'ones' and 'twos' removes the
// bits that have appeared three times.
mask = ~(ones & twos);
ones &= mask;
twos &= mask;
}
return ones;
}
public static void main(String[] args) {
int [] arr = {1, 10, 1, 1};
System.out.println(getSingle(arr));
}
}
def getSingle(arr):
ones, twos = 0, 0
for num in arr:
# Update 'twos' with bits that are set in both 'ones' and
# current number. These are bits that have appeared twice so far.
twos |= ones & num
# XOR current number with 'ones' to add bits appearing
# odd number of times.If a bit has appeared once, it is set
# if it's the second time, it gets unset.
ones ^= num
# (ones & twos) gives bits that are set in both, meaning they
# have now appeared 3 times. ~(ones & twos) inverts it to create
# a mask where those bits are 0 (to be cleared), and others are 1.
# Applying this mask on 'ones' and 'twos' removes the
# bits that have appeared three times.
mask = ~(ones & twos)
ones &= mask
twos &= mask
return ones
if __name__ == '__main__':
arr = [1, 10, 1, 1]
print(getSingle(arr))
using System;
using System.Collections.Generic;
class GfG {
static int getSingle(int [] arr) {
int ones = 0, twos = 0, mask;
foreach (int num in arr) {
// Update 'twos' with bits that are set in both 'ones' and
// current number. These are bits that have appeared twice so far.
twos |= ones & num;
// XOR current number with 'ones' to add bits appearing
// odd number of times.If a bit has appeared once, it is set
// if it's the second time, it gets unset.
ones ^= num;
// (ones & twos) gives bits that are set in both, meaning they
// have now appeared 3 times. ~(ones & twos) inverts it to create
// a mask where those bits are 0 (to be cleared), and others are 1.
// Applying this mask on 'ones' and 'twos' removes the
// bits that have appeared three times.
mask = ~(ones & twos);
ones &= mask;
twos &= mask;
}
return ones;
}
static void Main() {
int [] arr = { 1, 10, 1, 1 };
Console.WriteLine(getSingle(arr));
}
}
function getSingle(arr) {
let ones = 0, twos = 0;
for (let num of arr) {
// Update 'twos' with bits that are set in both 'ones' and
// current number. These are bits that have appeared twice so far.
twos |= ones & num;
// XOR current number with 'ones' to add bits appearing
// odd number of times.If a bit has appeared once, it is set
// if it's the second time, it gets unset.
ones ^= num;
// (ones & twos) gives bits that are set in both, meaning they
// have now appeared 3 times. ~(ones & twos) inverts it to create
// a mask where those bits are 0 (to be cleared), and others are 1.
// Applying this mask on 'ones' and 'twos' removes the
// bits that have appeared three times.
let mask = ~(ones & twos);
ones &= mask;
twos &= mask;
}
return ones;
}
const arr = [1, 10, 1, 1];
console.log(getSingle(arr));
Output
10