题意:
给定一个整数数组 A,找出索引为 (i, j, k) 的三元组,使得:
0 <= i < A.length
0 <= j < A.length
0 <= k < A.length
A[i] & A[j] & A[k] == 0,其中 & 表示按位与(AND)操作符。
方法一:哈希表暴力解
class Solution {
public:
int countTriplets(vector<int>& nums) {
int total = 0;
unordered_map<int,int> mp1;//哈希表1,<数字,出现次数>
unordered_map<int,int> mp2;//哈希表2,<两数与的结果,出现次数>
for(int& num:nums)//更新哈希表1
{
mp1[num]++;
}
int len = nums.size();//统计nums的长度
for(int i=0;i<len;i++)//更新哈希表2
{
for(int j=0;j<len;j++)
{
mp2[nums[i]&nums[j]]++;
}
}
for(auto iter1=mp1.begin();iter1!=mp1.end();iter1++)//利用迭代器,统计最后结果
{
for(auto iter2=mp2.begin();iter2!=mp2.end();iter2++)
{
if((iter1->first&iter2->first)==0)
total+=iter2->second*iter1->second;
}
}
return total;
}
};
方法二:位运算,通过确定上界,来确定掩码,向下枚举每种情况,最后对结果进行累加
class Solution {
public:
int countTriplets(vector<int>& nums) {
int total = 0;
int k = 1;//用来确定掩码,掩码是由全1组成的数字
for(int& num:nums)//确定上界,进而确定掩码
{
while(k<=num)
{
k<<=1;
}
}
unordered_map<int,int> mp;//哈希表,<和key值进行与操作能等于0的数字,这样的数字由多少>
for(int& num:nums)
{
int mask = (k-1)^num;//k-1是掩码,格式类似于0001111111...111111,^进行异或操作,找到剩下的那些1
int i=mask;
for(int i=mask;i!=0;i=(i-1)&mask)//向下遍历枚举每个能和num进行与操作结果等于0的数字
{
mp[i]++;
}
mp[0]++;//0与任何数进行与操作,结果都是0,所以必须最后再加上一次
}
for(int& a:nums)//遍历枚举,找到最后要返回的结果
{
for(int& b:nums)
{
total+=mp[a&b];//确定最后一个数字可以有多少种取法
}
}
return total;
}
};
转为vector实现哈希表,提高空间效率和时间效率,最后的结果提升到将近双百
class Solution {
public:
int countTriplets(vector<int>& nums) {
int total = 0;
int k = 1;//用来确定掩码,掩码是由全1组成的数字
for(int& num:nums)//确定上界,进而确定掩码
{
while(k<=num)
{
k<<=1;
}
}
vector<int> mp(k,0);//哈希表,<和key值进行与操作能等于0的数字,这样的数字由多少>
for(int& num:nums)
{
int mask = (k-1)^num;//k-1是掩码,格式类似于0001111111...111111,^进行异或操作,找到剩下的那些1
int i=mask;
for(int i=mask;i!=0;i=(i-1)&mask)//向下遍历枚举每个能和num进行与操作结果等于0的数字
{
mp[i]++;
}
mp[0]++;//0与任何数进行与操作,结果都是0,所以必须最后再加上一次
}
for(int& a:nums)//遍历枚举,找到最后要返回的结果
{
for(int& b:nums)
{
total+=mp[a&b];//确定最后一个数字可以有多少种取法
}
}
return total;
}
};