位运算相关算法

有1个数字只出现一次,其余数字均出现2次

思想:使用异或,遍历数组,两两异或,即是最终的答案

  • 时间复杂度:O(n)

找出缺失的数字

给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。
思想:采用异或

  • 数组内的所有元素先异或一次
  • step1的结果在与 0~list.size() 每个数字异或一次
  • 缺失的那个数字必然只被异或1次,其余数字参与了2次异或,最终的结果就是那个缺失的数字

有1个数字只出现一次,其余数字均出现3次

思想1:将每个数字看成32个bit位,对每一位,遍历整个数组,统计数组中该位为1的个数,当个数%3不为0时,该位为有效位
最终32位中的有效位组成的数字,即是只出现一次的数字

  • 该方法为求解此类问题的通用方法
  • 时间复杂度O(32n)
int find_num(int* nums, int len) 
{
    int ret = 0;
    for (int i = 0; i < 32; i++) 
    {
        int mask = 1 << i;
        int cnt = 0;
        for (int j = 0; j < len; j++) 
        {
            if ((nums[j] & mask) != 0)
            {
                cnt++;
            }
        }
        if (cnt % 3 != 0) 
        {
            ret |= mask;
        }
    }
    return ret;
}

思想2:设置3个变量 个人感觉不是很好想到

  • 位为1的位置,出现的次数超过1次 (more_one)
  • 位为1的位置,出现的次数为奇数次 (odd)
  • 微为1的位置,出现3次
  • 时间复杂度O(n)
int find_num(int* nums, int len)
{
    int more_one = 0;
    int odd = 0;
    int three = 0;
    for (int i = 0; i < len; i++)
    {
        more_one = more_one | (odd & nums[i]);
        odd = odd ^ nums[i];
        three = more_one & odd;
        // 出现三次的位置 清空
        more_one = more_one & (~three);
        odd = odd & (~three);
    }
    // 根据题目,最后出现奇数次的,到此为止,只出现了1次
    return odd;
}

有2个数字只出现1次,其余数字均出现2次

思路:

  • 遍历所有元素求异或,其结果为2个只出现1次的数字的异或值
  • 随便找第一步中值二进制位为1的位置,按照该位是否为1,将原始数组分为2个数组
  • 分别对上面求出的两个数组中的元素求异或即可得到2个只出现1次的数字

所有小写英文字母a~e,求其顺序子集

eg:{a},{ab},{ac},{abc}
思路:
将a~e这5个英文字母组合,看成[00001-11111]区间内的数字
每一个数字,即对应一套子集

比特计数

给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
思路:奇数偶数分开来看

  • 对偶数2n,2n的中1出现的次数与n中1出现的次数相同
  • 对奇数2n+1,二进制的最后一位肯定是1,2n+1中1出现的次数比n中1出现的次数多1
std::vector calcbits(int num)
{
    std::vector<int> res;
    res.emplace_back(0);
    if (num == 0)
    {
        return res;
    }
    for (int i = 1; i <= num; i++)
    {
        if (i % 2 == 0)
        {
            res.emplace_back(res[i / 2]);
        }
        else
        {
            res.emplace_back(res[i / 2] + 1);
        }
    }
    return res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值