【算法技巧】位运算

目录

  • 1.概述
  • 2.位运算技巧
    • 2.1.与运算 (&)
      • 2.1.1.判断奇偶性
      • 2.1.2.判断一个数是否是 2 的幂
      • 2.1.3.将英文字母转换为大写
      • 2.1.4.代替取模运算
    • 2.2.或运算 (|)
      • 2.2.1.将英文字母转换为小写
    • 2.3.异或运算 (^)
      • 2.3.1.消除成对相同的数
      • 2.3.2.不使用临时变量来交换两个数
      • 2.3.3.进行英文字母大小写互换
      • 2.3.4.判断两个数是否异号
    • 2.4.取反运算 (~)
      • 2.4.1.自增
      • 2.4.2.自减
    • 2.5.移位运算 (<<、>>、>>>)
      • 2.5.1.乘以 2
      • 2.5.2.除以 2
  • 3.应用

1.概述

(1)位运算是一种直接对二进制位进行操作的运算方式。它们是在计算机中对数据的底层操作,通常在位级别上进行,不考虑数据的整体值。在 Java 中,位运算符有以下几种:

  • 与运算 (&):对两个操作数的每一位进行与操作,只有当对应的位都为 1 时,结果为 1,否则为 0。
  • 或运算 (|):对两个操作数的每一位进行或操作,只要对应的位至少有一个为 1,结果为 1,否则为 0。
  • 异或运算 (^):对两个操作数的每一位进行异或操作,只有当对应的位不同时,结果为 1,否则为 0。
  • 取反运算 (~):对一个操作数的每一位进行取反操作,将 0 变为 1,将 1 变为 0。
  • 左移运算 (<<):将一个操作数的所有位向左移动指定的位数,低位补 0。
  • 右移运算 (>>):将一个操作数的所有位向右移动指定的位数,高位的处理取决于具体情况。
  • 无符号右移运算 (>>>):将一个操作数的所有位向右移动指定的位数,高位总是补 0。

(2)位运算常用于编程中的一些特定场景,如位掩码位集合操作优化算法设计以及操作硬件等。它们在处理位级别的数据和优化性能方面非常有用。

有关位运算的更多技巧,可以参考 Bit Twiddling Hacks。

2.位运算技巧

2.1.与运算 (&)

2.1.1.判断奇偶性

判断奇偶性:位运算中最低位为 1 表示奇数,为 0 表示偶数。

(n & 1) == 1	// n 为奇数
(n & 1) == 0	// n 为偶数

2.1.2.判断一个数是否是 2 的幂

如果一个数是 2 的幂,那么它的二进制形式中只有最高位为 1,其他位都是 0。

(n & (n - 1)) == 0	// x 是 2 的幂
(n & (n - 1)) == 1	// x 不是 2 的幂

n & (n - 1) 的作用是消除数字 n 的二进制表示中的最后一个 1。因此,如果 n 是 2 的幂,那么 n 的二进制表示中只有一个 1,所以 n & (n - 1) 的结果必为 0。

2.1.3.将英文字母转换为大写

我们可以通过将小写字母与下划线 ‘_’ 进行与操作,将其转换为对应的大写字母。

(char) ('n' & '_') = 'N'
(char) ('N' & '_') = 'N'[添加链接描述](https://xgqngu.blog.csdn.net/article/details/130137431)
  • 在位运算中,字符在内存中以数字的形式表示。在大部分字符编码中(如 ASCII 码),大写字母的编码值比小写字母的编码值要小
  • 在 ASCII 编码中,大写字母和小写字母的 ASCII 码值之间的差值为固定的 32(或二进制的 0010 0000),例如,字母 ‘A’ 的 ASCII 码值为 65,而字母 ‘a’ 的 ASCII 码值为 97,它们之间的差值就是 32。
  • 而 ‘_’ 的二进制表示为 0101 1111,小写字母 a-z 的 ASCII 值范围为 97-122,即 0110 0001-0011 1101;
  • 那么小写字母与 ‘_’ 相与后,相当于其对应 ASCII 值减少了 32,因此也就转换为了对应的大写字母

2.1.4.代替取模运算

(1)一般来说,我们要求 h 除以 n 的余数,会通过取模运算 (%),即 h % n。但当 n 是 2 的幂次方时,我们可以使用位运算来代替取模运算,从而达到提高计算效率的目的,即:

h % n == hash & (n - 1)	// n 是 2 的幂次方

(2)当 n 是 2 的幂次方时,它的二进制表示为 100…00(n 个 0)。这意味着 n - 1 的二进制表示为 011…11(n 个 1)。因此,按位与运算 h & (n - 1) 实际上是将 h 的二进制表示的最后 n 位保留,其他位都设为 0,起到了取模的效果。

(3)在这种情况下进行替换有一些具体的应用场景,例如 HashMap 中数组 table 长度被设置为 2 的 n 次方中的一个目的就是上面提到的提高计算效率,具体细节可以参考 Java 基础——HashMap 底层数据结构与源码分析这篇文章中的 3.1 章节。

2.2.或运算 (|)

2.2.1.将英文字母转换为小写

我们可以通过将大写字母与空格 ’ ’ 进行或操作,将其转换为对应的小写字母。

(char) ('N' | ' ') = 'n'
(char) ('n' | ' ') = 'n'
  • 其原理与上面的通过与操作将英文字符转换为大写类似,空格字符在 ASCII 编码中的值为 32(十进制),其二进制表示为 0010 0000
  • 而大写字母 A-Z 的 ASCII 值范围为 65-90,即 0110 0001-0011 1101
  • 那么大写字母与 ’ ’ 相或后,相当于其对应 ASCII 值增加了 32,因此也就转换为了对应的小写字母

2.3.异或运算 (^)

2.3.1.消除成对相同的数

(1)异或运算有两个非常重要的性质:

  • 一个数和 0 做异或运算的结果为它本身,即 a ^ 0 = a。
  • 一个数和它本身做异或运算结果为 0,即 a ^ a = 0;

(2)其中,第二条性质明显有一个重要的用途,即消除成对相同的数,如果再结合异或运算的交换律,那么我们可以很迅速地解决 136.只出现一次的数字这题,即给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素

class Solution {public int singleNumber(int[] nums) {int single = 0;/*对于本题,只要把所有数字进行异或,成对的数字就会变成 0,落单的数字和 0 做异或还是它本身,所以最后异或的结果就是只出现⼀次的元素。*/for (int num : nums) {single ^= num;}return single;}
}

268.丢失的数字 这题也可以通过这个技巧来解决。

2.3.2.不使用临时变量来交换两个数

int a = -1;
int b = 2;
a ^= b;
b ^= a;
a ^= b;
System.out.println("a = " + a);     // a = 2
System.out.println("b = " + b);     // b = -1

其实,上面不使用临时变量来交换两个数是基于 a ^ a = 0 这一性质实现的,具体推导过程如下:

a ^= b;		// a1 = a ^ b
b ^= a;		// b1 = b ^ a1 = b ^ (a ^ b) = a
a ^= b;		// a2 = a1 ^ b1 = (a ^ b) ^ a = b

2.3.3.进行英文字母大小写互换

(char) ('n' ^ ' ') = 'N'
(char) ('N' ^ ' ') = 'n'
  • 其原理与上面的通过与操作将英文字符转换为大写类似,空格字符在 ASCII 编码中的值为 32(十进制),其二进制表示为 0010 0000
  • 而大写字母 A-Z 的 ASCII 值范围为 65-90,即 0110 0001-0011 1101
  • 而小写字母 a-z 的 ASCII 值范围为 97-122,即 0110 0001-0011 1101
  • 大小写字母与 ’ ’ 相异后,小写字母对应 ASCII 值减少了 32,大写字母对应 ASCII 值增加了 32,因此也就进行了英文字母大小写互换

2.3.4.判断两个数是否异号

计算机底层中整数通常使用补码来表示,通过位运算判断两个数是否异号的原理是就是利用了补码表示中最高位符号位的特性。默认情况下,整数的最高位为符号位,0 表示正数,1 表示负数。通过位运算判断两个数是否异号的步骤如下:

  • 对两个数进行异或运算 (^)。异或运算的结果在二进制表示中,两个数对应位相同则为 0,相异则为 1。
  • 如果结果小于 0,则说明这两个数异号;如果结果大于 0,则说明这两个数同号。
int a = 1;
int b = 2;
System.out.println(((a ^ b) < 0));  // false,a 和 b 同号int c = -1;
int d = 2;
System.out.println(((c ^ d) < 0));  // true,a 和 b 异号

2.4.取反运算 (~)

2.4.1.自增

int n = 2;
n = -~n;
System.out.println(n);	// 3

2.4.2.自减

int n = 2;
n = ~-n;
System.out.println(n);	// 1

2.5.移位运算 (<<、>>、>>>)

2.5.1.乘以 2

在二进制表示中,将一个数乘以 2 就等于将它向左移动 1 位,低位补 0。

int n = 3;
n <<= 1;
System.out.println(n);		// 6

2.5.2.除以 2

在二进制表示中,将一个数乘以 2 就等于将它向右移动 1 位,高位补符号位。

int n = 4;
n >>= 1;
System.out.println(n);		// 2

更多有关 Java 中移位运算符的细节可以参考 Java 基础面试题——运算符这篇文章。

3.应用

大家可以去 LeetCode 上找相关的位运算的题目来练习,或者也可以直接查看 LeetCode 算法刷题目录 (Java) 这篇文章中的位运算章节。如果大家发现文章中的错误之处,可在评论区中指出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/168029.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一起学docker系列之八使用 Docker 安装配置 MySQL

目录 前言步骤 1&#xff1a;拉取 MySQL 镜像步骤 2&#xff1a;运行 MySQL 容器步骤 3&#xff1a;检查容器状态步骤 4&#xff1a;进入 MySQL 容器步骤 5&#xff1a;配置 MySQL 字符编码步骤 6&#xff1a;重启 MySQL 容器步骤 7&#xff1a;测试字符编码步骤 8&#xff1a;…

防止应用程序截屏(容器式,防止极域电子教室和录屏软件录制)

核心原理、实现目的 1、使用Panel容器将外部窗口嵌入自己写的程序 2、使用防止截屏的函数来对窗口透明&#xff0c;这可以使本窗口内所有窗口在录屏软件上消失 3、解放&#xff0c;抓取&#xff0c;存储句柄&#xff0c;实现摆脱录屏&#xff08;极域监控&#xff09; 程序…

用 Addon 增强 Node.js 和 Electron 应用的原生能力

前言 Node.js Addon 是 Node.js 中为 JavaScript 环境提供 C/C 交互能力的机制。其形态十分类似 Java 的 JNI&#xff0c;都是通过提供一套 C/C SDK&#xff0c;用于在 C/C 中创建函数方法、进行数据转换&#xff0c;以便 JavaScript / Java 等语言进行调用。这样编写的代码通常…

Spring - Mybatis-设计模式总结

Mybatis-设计模式总结 1、Builder模式 2、工厂模式 3、单例模式 4、代理模式 5、组合模式 6、模板方法模式 7、适配器模式 8、装饰者模式 9、迭代器模式 虽然我们都知道有26个设计模式&#xff0c;但是大多停留在概念层面&#xff0c;真实开发中很少遇到&#xff0c;…

【数据结构】时间和空间复杂度

马上就要进入到数据结构的学习了 &#xff0c;我们先来了解一下时间和空间复杂度&#xff0c;这也可以判断我们的算法是否好坏&#xff1b; 如何衡量一个算法的好坏&#xff1f; 就是看它的算法效率 算法效率 算法效率分析分为两种&#xff1a;第一种是时间效率&#xff0c;第…

C++ Qt QVariant类型使用介绍与代码演示

作者:令狐掌门 技术交流QQ群:675120140 csdn博客:https://mingshiqiang.blog.csdn.net/ 文章目录 一、QVariant基本用法二、自定义类型使用QVariant三、其它用法赋值修改和替换值使用`QVariant::setValue()`设置值复制构造函数和赋值操作比较使用`QVariant::swap()`交换值使…

CVE-2023-22515:Atlassian Confluence权限提升漏洞复现 [附POC]

文章目录 Atlassian Confluence权限提升(CVE-2023-22515)漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 Atlassian Confluence权限提升(CVE-2023-22515)漏洞复现 [附POC] 0x01 前言 免责声明&…

vue中下载文件后无法打开的坑

今天在项目开发的时候临时要添加个导出功能我就写了一份请求加导出得代码&#xff0c; 代码&#xff1a; //导出按钮放开exportDutySummarizing (dataRangeInfo) {const params {departmentName: dataRangeInfo.name,departmentQode: dataRangeInfo.qode}//拼接所需得urlcons…

UserRole

Qt::UserRole 是 Qt::ItemDataRole 枚举中的一个成员&#xff0c;用于表示自定义数据角色&#xff08;Data Role&#xff09;的起始值。 在 Qt 中&#xff0c;Qt::ItemDataRole 枚举用于标识项&#xff08;Item&#xff09;中不同类型的数据。这些数据角色包括 Qt::DisplayRol…

目标检测YOLO系列从入门到精通技术详解100篇-【目标检测】红外热成像

目录 前言 知识储备 红外热成像仪基础知识 算法原理 红外热成像探测距离 红外图像增强

第一百七十八回 介绍一个三方包组件:SlideSwitch

文章目录 1. 概念介绍2. 使用方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"如何创建垂直方向的Switch"相关的内容&#xff0c;本章回中将 介绍SlideSwitch组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们…

多功能智能灯杆主要功能有哪些?

多功能智能灯杆这个词相信大家都不陌生&#xff0c;最近几年多功能智能灯杆行业发展迅速&#xff0c;迅速取代了传统路灯&#xff0c;那么多功能智能灯杆相比传统照明路灯好在哪里呢&#xff0c;为什么大家都选择使用叁仟智慧多功能智能灯杆呢&#xff1f;所谓多功能智能灯杆着…

【libGDX】Mesh纹理贴图

1 前言 纹理贴图的本质是将图片的纹理坐标与模型的顶点坐标建立一一映射关系。纹理坐标的 x、y 轴正方向分别朝右和朝下&#xff0c;如下。 2 纹理贴图 本节将使用 Mesh、ShaderProgram、Shader 实现纹理贴图&#xff0c;OpenGL ES 的实现见博客 → 纹理贴图。 DesktopLauncher…

超级应用平台(HAP)起航

各位明道云用户和伙伴&#xff0c; 今天&#xff0c;我们正式发布明道云10.0版本。从这个版本开始&#xff0c;我们将产品名称正式命名为超级应用平台&#xff08;Hyper Application Platform, 简称HAP&#xff09;。我们用“超级”二字表达产品在综合能力方面的突破&#xff…

清华系下一代 LCM

LCM LoRA模型是一种创新的深度学习模型&#xff0c;它通过特殊的技术手段&#xff0c;显著提高了图像生成的效率。这种模型特别适用于需要快速生成高质量图像的场景&#xff0c;如艺术创作、实时图像处理等。 GitHub - luosiallen/latent-consistency-model: Latent Consistenc…

视频监控中的智能算法与计算机视觉技术

智能视频监控是一种基于人工智能技术的监控系统&#xff0c;它能够通过对图像和视频数据进行分析&#xff0c;自动识别目标物体、判断其行为以及进行异常检测等功能&#xff0c;从而实现对场景的智能化监管。以下是常见的一些用于智能视频监控的算法&#xff1a; 1、人脸识别技…

RabbitMQ简易安装

一般来说安装 RabbitMQ 之前要安装 Erlang &#xff0c;可以去Erlang官网下载。接着去RabbitMQ官网下载安装包&#xff0c;之后解压缩即可。 Erlang官方下载地址&#xff1a;Downloads - Erlang/OTP RabbitMQ官方下载地址&#xff1a;Downloading and Installing RabbitMQ —…

org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder

密码&#xff0c;加密&#xff0c;解密 spring-security-crypto-5.7.3.jar /** Copyright 2002-2011 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with t…

Kafka(一)

一&#xff1a;简介 解决高吞吐量项目的需求 是一款为大数据而生的消息中间件&#xff0c;具有百亿级tps的吞吐量&#xff0c;在数据采集、传输、存储的过程中发挥着作用 二&#xff1a;为什么要使用消息队列 一个普通访问量的接口和一个大并发的接口&#xff0c;它们背后的…

C/C++---------------LeetCode第1512. 好数对的数目

好数对的数目 题目及要求暴力算法哈希算法在main内使用 题目及要求 给你一个整数数组 nums 。 如果一组数字 (i,j) 满足 nums[i] nums[j] 且 i < j &#xff0c;就可以认为这是一组 好数对 。 返回好数对的数目。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3,1,…