2 异或位运算大厂必刷题

如何不用额外变量交换两个数

int a,b;

a=a^b;
b=a^b;
a=a^b;

注意事项:

  • a和b必须是两块独立的内存.

一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数

题解

  • 解法1: 哈希表做词频统计
  • 解法2: 只用一个变量遍历一遍
    • 用eor异或所有人, 把最后结果留在自己身上, 这么干完一遍之后,最后你返回eor的值就是那个出现了奇数次的数.

怎么把一个int类型的数,提取出最右侧的1来

题意:
在这里插入图片描述

题解:

  • a&(~a + 1)
  • 等同于
  • a & (-a)

在这里插入图片描述

怎么把一个int类型的数,获取位数为1的数量

int a;
int nums=0;
while(a)
{
	a=a&(a-1);
	nums++;
}

一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数

题解1:
最常见的解题步骤,面试要求的

void printOddTimesNums(vector<int>& v)
{
    int eor=0;
    for(auto e: v)eor^=e;
    // 假设 a 和 b 是 两种奇数.
    // 从 eor 里随便取一个一位置的数,我们统一取最右侧
    // right = eor & (~eor+1)
    int right = eor & (-eor);
    // 
    // 共有a和b两类的数据 , 将两类数据区分 
    // 我们假设最右侧为1是 属于a类的数据
    // 能够与right按位与不等与0 ,说明属于a类
    int a = 0;
    for(auto e : v)
    {
        if(e & right)
        {
            a^=e;
        }
    }
    int b = eor ^ a;
        cout<< "a="<<a<<endl;
    cout<<"b="<<b<<endl;
    
}

题解2:

void test()
{
    vector<int> v = {1,1,2,2,3,3,3,5,44,55,66,44,55,66,66,66};
    int a =0,b=0;
    int eor =0;
    for(auto e:v)
    {
        eor^=e;
    }
    // eor = a^b
    
    int tmp=eor;
    int i=0;
    int pre=0; // 求出a或者b的数
    while(tmp)
    {
        pre=tmp;
        tmp^=v[i];
        i++;
    }
    cout<< "a="<<pre<<endl;
    cout<<"b="<<(pre^eor)<<endl;
}

一个数组中有一种数出现K次,其他数都出现了M次

题意:一个数组中有一种数出现K次a元素,其他数都出现了M次,M> 1,K<M我到,出现了次的数,要求,额外空复杂度0(1),时间复杂度ON)。

题解:

  • 开一个 32位int的数组 v
  • if v[i] % m == 0 说明 二进制第i位没出现过a元素。
int onlyKTimes(vector<int> &v, int k, int m)
{
    vector<int> t(32, 0);
    // t[0] 0位置的1出现了几个
    // t[i] i位置的1出现了几个
    for (auto num : v)
    {
        for (int i = 0; i <= 31; i++)
        {
            if ((num >> i) & 1 == 1)
            {
                t[i]++;
            }
        }
    }
    int ans = 0;
    for (int i = 0; i <= 31; i++)
    {
        if (t[i] % m != 0)
        {
            ans |= (1 << i);
        }
    }
    return ans;
}

对数器验证算法:

int testonlyKTimes(vector<int> &v, int k, int m)
{
    unordered_map<int, int> map;
    for (auto num : v)
    {
        if (map.find(num) != map.end())
        {
            map[num]++;
        }
        else
        {
            map[num] = 1;
        }
    }
    int ans = 0;
    for (auto num : map)
    {
        if (num.second == k)
        {
            ans = num.first;
            break;
        }
    }
    return ans;
}

vector<int> randomArray(int kinds, int range,int k, int m)
{
    int kNum = rand()% range + 1;
    int times = k; // kNum 出现k次
    int numkinds = rand() % kinds + 1;
    // k*1 + (numkinds - 1) * m;
    vector<int> v(k+ (numkinds-1)*m);
    int index = 0 ;
    for(;index<times;index++)
    {
        v[index] = kNum;
    }
    numkinds--;
    unordered_set<int> set;
    set.insert(kNum);
    while(numkinds!=0)
    {
        int curNum = 0 ;
        do{
            curNum = rand() % range +1;
        }while(set.find(curNum)!=set.end());
        set.insert(curNum);
        numkinds--;
        for(int i=0;i<m;i++)
        {
            v[index++]=curNum;
        }
    }
    // v 填好了
    // 由于数据太整齐了,我们打乱数据
    for(int i=0;i<v.size();i++)
    {
        int j = rand() % v.size() ; // 0 ~ size-1;
        int tmp = v[i];
        v[i]=v[j];
        v[j]=tmp;
    }
    return std::move(v);
}
// 对数器
void test2()
{
    srand((int)time(NULL));
    int kinds = 100;         // 元素种类 1~ 100
    int range = 300;        // 元素范围 1~300
    int testTime = 1000; // 测试次数
    int max = 9;           // k,m 范围 1~9
    cout << "测试开始\n";
    while (testTime--)
    {
        int a = rand()%max + 1;
        int b = rand()%max + 1;
        int k = std::min(a,b);
        int m = std::max(a,b);
        if(k==m){
            m++;
        }


        vector<int> v = randomArray(kinds, range, k, m);
        int ans1 = onlyKTimes(v, k, m);
        int ans2 = testonlyKTimes(v, k, m);
        if (ans1 != ans2)
        {
            cout << "出错了\n";
        }
    }
    cout << "测试结束\n";
}
int main()
{
    test2();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2023框框

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值