欢迎光临
我们一直在努力

【位运算】5 道经典入门 LeetCode 位运算题整理

前言

最近学习位运算,一开始觉得很抽象、难理解,慢慢刷题后才发现:位运算其实就几个固定技巧,题目都是套路。这篇是我的学习整理,适合和我一样刚入门的同学。

6 个常用位运算核心技巧

这些技巧不用一下子全懂,做题时慢慢体会:

  • 异或^:相同为0,不同为1,任何数和自己异或为0。作用:去重、查找只出现一次的数字
  • 获取第 i 位:n & (1 << i)
  • 消除最后一个1:n & (n – 1)。作用:统计 1 的个数、判断 2 的幂
  • 保留最后一个1:n & -n
  • 把第 i 位设为1:res |= (1 << i)
  • 左移<<、右移>>:等价于乘 2 / 除 2
  • 一、只出现一次的数字

    题目

    136. 只出现一次的数字 给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

    你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

    思路

    利用异或抵消:

    • 出现两次的数异或 → 0
    • 0 异或答案 → 答案所以把数组全部异或一遍,剩下的就是只出现一次的数字。

    代码

    class Solution {
    public:
    int singleNumber(vector<int>& nums) {
    int len = nums.size();
    int res = 0;
    for (int i = 0; i < len; i++) {
    res ^= nums[i];
    }
    return res;
    }
    };

    二、颠倒二进制位

    题目

    190. 颠倒二进制位 颠倒给定的 32 位有符号整数的二进制位。

    这道题在 LeetCode 190.颠倒二进制位 | 从暴力解法到位运算魔法-CSDN博客 中有详细讲解。

    思路

    一位一位取出来,再一位一位放到结果里,相当于把二进制 “倒过来”。

    代码

    class Solution {
    public:
    uint32_t reverseBits(uint32_t n) {
    uint32_t res = 0;
    for (uint32_t i = 0; i < 32; i++) {
    uint32_t bit = n >> i & 1; // 从右往左取n的每一位数字
    res <<= 1; // res整体往左挪一位,空出最右边的位置
    res |= bit; // 将取出的数字放在res的最右边
    }
    return res;
    }
    };

    三、位1的个数

    题目

    191. 位1的个数 给定一个正整数 n,编写一个函数,获取一个正整数的二进制形式并返回其二进制表达式中 设置位 的个数(也被称为汉明重量)。

    思路

    技巧:n & (n-1) 会消除最后一个 1

    消除几次,就有几个 1。

    代码

    class Solution {
    public:
    int hammingWeight(int n) {
    int res = 0;
    while (n) {
    n &= n – 1; // 消除最后一个1
    res++; // 消除次数=1的个数
    }
    return res;
    }
    };

    四、2的幂

    题目

    231. 2 的幂 给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。

    思路

    2的幂的二进制特点:有且只有一个1

    消除最后一个 1 后一定变成 0,同时要保证 n > 0

    代码

    class Solution {
    public:
    bool isPowerOfTwo(int n) {
    if (n <= 0) { // 只有正整数才能为2的幂次方
    return false;
    }
    n &= (n – 1); // 消除最后一个1
    return n == 0; // 2的幂次方只有一个1,消除之后n=0
    }
    };

    五、丢失的数字

    题目

    268. 丢失的数字 给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

    思路

    依旧是异或去重:可以使res(初始为n)异或0~n-1,同时异或数组的元素,最终这个数的结果就是丢失的数字。因为数组中的存在的数字被异或了两次,只有丢失的数字只被异或了一次。

    代码

    class Solution {
    public:
    int missingNumber(vector<int>& nums) {
    int n = nums.size();
    int res = n;
    for (int i = 0; i < n; i++) {
    res ^= i;// 异或0~n-1
    res ^= nums[i];// 异或数组中的数字
    }
    return res;
    }
    };

    学习小结

    位运算刚学的时候确实不太习惯,但刷完这几道题发现:题目考来考去,都是那几个固定技巧。

    • 看到重复、消失、只出现一次 → 想异或
    • 看到统计 1、2 的幂 → 想 n & (n-1)
    • 看到二进制翻转 → 想移位 + 取位

    继续多练几道,应该就能越来越熟练了。

    赞(0)
    未经允许不得转载:171主机测评 » 【位运算】5 道经典入门 LeetCode 位运算题整理
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址