Who is the intruder ?
Problem statement
Let an array of integers where each element is repeated 3 times except one of them which
is unique.
The goal is to find this element. The solution must have a linear time complexity O(n)
and a constant memory complexity O(1).
For example, if we consider the following array: [4 7 8 4 5 7 8 4 7 8] then the solution must return 5.
Reasonning step
The solution is not so intuitive but very elegant.The idea is to turn the numbers of the array into their representation in base 3. The digits of the numbers are then added. The sum of the digits is then divided by 3 and we consider only the rest. The resting digits represents the unique number.
For example, if we consider the previous array. The representation in base 3 of the numbers are:
- 4 -> 11
- 7 -> 21
- 8 -> 22
- 4 -> 11
- 5 -> 12
- 7 -> 21
- 8 -> 22
- 4 -> 11
- 7 -> 21
- 8 -> 22
The rest of the division by 3 is 2.
The sum of all the second digits is: 1 + 2 + 2 + 1 + 1 + 2 + 2 + 1 + 2 + 2 = 16.
The rest of the division by 3 is 1.
The number is then 12 in base 3 which is 5, i.e the unique number!
Indeed, since all the elements are repeated three times except one, when we do the sum of,
let say, the first digits we have a number which can be written : 3n * 2 + 3m * 1 + (0 or 1 or 2)
The modulo of this number by 3 is equal to the last term, i.e (0 or 1 or 2), which is the first digit of the unique element ;)
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
std::string convertToBase(int base, int num);
std::vector<std::string> convertIntegerVectorToBaseVector(int base,
std::vector<int>& nums);
int getUniqueElement(int base, std::vector<int>& nums);
int main(int argc, char *argv[])
{
std::vector<int> nums(10);
nums[0] = 14; nums[1] = 8; nums[2] = 26;
nums[3] = 14; nums[4] = 8; nums[5] = 26;
nums[6] = 4;
nums[7] = 14; nums[8] = 8; nums[9] = 26;
std::cout << getUniqueElement(3, nums) << std::endl;
return 0;
}
std::vector<std::string> convertIntegerVectorToBaseVector(int base,
std::vector<int>& nums)
{
std::vector<std::string> baseNums;
baseNums.reserve(nums.size());
for(auto& n: nums)
baseNums.push_back(convertToBase(base, n));
return baseNums;
}
int getUniqueElement(int base, std::vector<int>& nums)
{
std::vector<std::string> baseNums;
baseNums.reserve(nums.size());
for(auto& n: nums)
baseNums.push_back(convertToBase(base, n));
int maxSize = 0;
for(auto& s : baseNums)
{
if(maxSize < s.size())
maxSize = s.size();
}
int unique[maxSize];
for(int i=0; i<maxSize; i++)
unique[i] = 0;
for(auto& s: baseNums)
{
for(int k=0; k<s.size(); k++)
unique[k] += static_cast<int>(s[k]-'0');
}
int res = 0;
int power = 1;
for(int i=0; i<maxSize; i++)
{
unique[i] %= base;
res += unique[i] * power;
power *= base;
}
return res;
}
std::string convertToBase(int base, int num)
{
std::string result = "";
while(num)
{
result = result + std::to_string(num % base);
num /= base;
}
return result;
}