王清欢Randy 王清欢Randy
首页
  • 编程语言

    • C/C++ 学习笔记
    • Golang 学习笔记
  • 算法分析

    • LeetCode 刷题笔记
  • 操作系统

    • Linux 基础
    • Vim 实用技巧
    • Shell 脚本编程
    • GDB 学习笔记
  • 开发工具

    • Git 学习笔记
  • 分布式理论

    • 共识算法
    • 分布式事务
  • 数据库内核

    • PostgreSQL
    • Postgres-XL
  • hidb
  • pgproxy
  • 实用技巧
  • 学习方法
  • 资源分享
GitHub (opens new window)
首页
  • 编程语言

    • C/C++ 学习笔记
    • Golang 学习笔记
  • 算法分析

    • LeetCode 刷题笔记
  • 操作系统

    • Linux 基础
    • Vim 实用技巧
    • Shell 脚本编程
    • GDB 学习笔记
  • 开发工具

    • Git 学习笔记
  • 分布式理论

    • 共识算法
    • 分布式事务
  • 数据库内核

    • PostgreSQL
    • Postgres-XL
  • hidb
  • pgproxy
  • 实用技巧
  • 学习方法
  • 资源分享
GitHub (opens new window)
  • 基础算法

    • 双指针

      • 双指针基础
      • 碰撞指针
      • 快慢指针
      • 滑动窗口
    • 二分查找

      • 基础应用
      • 边界收缩
      • 局部有序
    • 排序算法

      • 01八大排序
      • 02快速排序
      • 03归并排序
      • 04桶排序
      • 05堆排序
    • 优先搜索

      • 01递归
      • 02网格结构深度优先搜索
      • 03树结构深度优先搜索
      • 04图结构深度优先搜索
      • 05网格结构广度优先搜索
      • 06树结构广度优先搜索
      • 07图结构广度优先搜索
    • 回溯算法

      • 01递归
      • 02 子集问题
      • 03 全排列问题
      • 04 组合问题
      • 05 回溯搜索问题
  • 基础数据结构

    • 线性表与哈希表

      • 01数组
      • 02栈和队列
      • 03单调栈
      • 04优先队列
      • 05双端队列
      • 06哈希表
      • 07多重集合
      • 08前缀和
      • 09数据结构设计
    • 字符串

      • 01字符串比较
      • 02回文字符串
      • 03字符串匹配
      • 04字符串算术表达式
    • 单链表

      • 01链表基础操作
      • 02链表遍历
    • 二叉树

      • 01二叉树的属性
      • 02二叉树的操作
      • 03层次遍历
      • 04前中后序遍历
      • 05二叉搜索树的属性
      • 06二叉搜索树的操作
      • 07字典树
      • 08二叉搜索树BST
    • 图

      • 01二分图
      • 02拓扑排序
      • 03并查集
      • 04最小生成树
      • 05最短路径
  • 进阶算法

    • 贪心算法

      • 01跳跃游戏
      • 02分配问题
      • 03区间问题
    • 分治策略

    • 动态规划

      • 01一维动态规划
      • 02二维动态规划
      • 03分割型动态规划
      • 04子序列问题
      • 05背包问题
      • 06字符串编辑问题
      • 07股票交易问题
  • 其他内容

    • 数学问题

      • 01公倍数与公因数
      • 02质数问题
      • 03进制转换问题
      • 04数字字符串求和问题
      • 05众数问题
      • 06中位数问题
      • 07数字处理问题
      • 08随机数问题
    • 位运算

      • 01位运算基础
        • 01 位运算基础
          • 461 汉明距离
          • 190 颠倒二进制位
          • 693 交替位二进制数
      • 02妙用异或运算
      • 03二进制特性
  • LeetCode刷题笔记
  • 其他内容
  • 位运算
王清欢
2023-03-24
目录

01位运算基础

# 01 位运算基础

​ 位运算是算法题里比较特殊的一种类型,它们利用二进制位运算的特性进行一些奇妙的优化和计算。常用的位运算符号包括:“∧” 按位异或、“&” 按位与、“|” 按位或、“∼” 取反、“<<” 算术左移和 “>>” 算术右移。以下是一些常见的位运算特性:

异或 与 或
x ^ 0000 = x x & 0000 = 0 x | 0000 = x
x ^ 1111 = ~x x & 1111 = x x | 1111 = 1111
x ^ x = 0 x & x = x x | x = x

​ 除此之外, n & (n - 1) 可以去除 n 的位级表示中最低的那一位,例如对于二进制表示 11110100,减去 1 得到 11110011,这两个数按位与得到 11110000。

​ n & (-n) 可以仅保留 n 的位级表示中最低的那一位,例如对于二进制表示 11110100,取负得到 00001100,这两个数按位与得到 00000100。

​ 回顾一下移位操作,移位操作是一种基本操作,是一种直接对二进制数据的位运算操作,移位运算又包含了逻辑移位(logical shift)和算术移位(arithmetic shift)两种。

  • 逻辑移位:移出去的位丢弃,空缺位(vacant bit)用 0 填充。
  • 算术移位:移出去的位丢弃,空缺位(vacant bit)用“符号位”来填充,所以一般用在右移运算中。

​ 无符号数,不管是左移还是右移都是逻辑移位;有符号数,做左移运算是逻辑移位,而做右移运算是算术移位。

# 461 汉明距离 (opens new window)

给定两个十进制数字,求它们二进制表示的汉明距离(Hamming distance,即不同位的个数)。

输入是两个十进制整数,输出是一个十进制整数,表示两个输入数字的汉明距离。

输入:x = 1, y = 4 输出:2 解释:1 (0 0 0 1);4 (0 1 0 0)

解析:

​ 求二进制数不同位的个数,直接使用将俩个数进行按位异或操作,不同位的结果就是 1,所以最终统计异或结果中的 1 的个数即可。

​ 计算二进制数 1 的个数的方法:不断将二进制数算数右移,将其与 1 进行与运算,如果末位是 1 则加入计数。

class Solution {
public:
    int hammingDistance(int x, int y) {
        // 异或运算
        int diff = x^y;
        int ans = 0;
        while(diff){
            // 与运算 判断末位是否为 1
            ans += diff & 1;
            // 算术右移动 将已经被统计的 1 移出
            diff = diff>>1;
        }
        return ans;
    }
};

# 190 颠倒二进制位 (opens new window)

给定一个十进制整数,输出它在二进制下的翻转结果。

输入和输出都是十进制整数。

输入:n = 00000010100101000001111010011100

输出:964176192 (00111001011110000010100101000000)

解释:将 n 的二进制串倒转

解析:

​ 使用算术左移和右移,可以很轻易地实现二进制的翻转。保存结果的二进制串每次向左移动一位腾出末位,然后将 n 与 1 取出 n 的末位并放入结果腾出的末位,放入之后 n 向右移动一位将已放入的位移出。

​ 一个简单的示例:

1 2 3 4 5
ans (算术左移) 0000 0000 0001 0010 0101
n (算术右移) 1010 0101 0010 0001 0000
class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        // 无符号32位整型
        uint32_t ans = 0;
        for(int i=0;i<32;++i){
            // 每次先将结果左移一位腾出位置
            ans <<= 1;
            // 将 n 当前的最后一位放到上一步ans腾出的位置(末位)
            ans += n&1;
            // 将已经放入结果的位移出
            n >>= 1;
        }
        return ans;
    }
};

# 693 交替位二进制数 (opens new window)

给定一个正整数,检查它的二进制表示是否总是 0、1 交替出现

输入一个整数,输出一个布尔类型表示二进制表示是否总是 0、1 交替出现

输入:n = 10
输出:true
解释:10 的二进制表示是:1010

解析:

​ 一种简单的思路是不断使用算术右移将n的二进制表示末位移出,使用按位与运算获取末位是0还是1,并且比较第 i 个和第 i-1 个末位是否相同,如果相同则直接返回false,检查完成则返回true。

class Solution {
public:
    bool hasAlternatingBits(int n) {
        // 记录第一个末位
        int pre = n & 1;
        n>>=1;
        while(n){
            // 比较第 i 个和第 i-1 个末位
            int now = n & 1;
            if(now == pre){
                return false;
            }else{
                // 更新前一个状态
                pre = now;
            }
            n >>= 1;
        }
        return true;
    }
};
上次更新: 2023/11/19, 12:55:48
08随机数问题
02妙用异或运算

← 08随机数问题 02妙用异或运算→

Theme by Vdoing | Copyright © 2023-2024 Wang Qinghuan | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式