异或运算

文章目录

    • 异或运算的概念
    • 异或运算的性质
    • 交换两个变量的值(不使用额外变量)
    • 只出现一次的数字
    • 只出现一次的数字 III
    • 只出现一次的数字 II

异或运算的概念

  • 对应二进制位进行异或运算
  • 对应二进制位上,相同结果为0,不同结果为1

小技巧:异或运算可以记为无进位相加

    现在有两个整数 A A A B B B A A A 等于7 , B B B等于13,那么 A A A^ B B B怎么运算呢?

// 十进制	A = 7		B = 13
// 二级制:
// A: 0111
// B: 1101
// --------
//    1010

     A A A ^ B = ( 1010 ) 2 = ( 10 ) 10 B = (1010)_2 = (10)_{10} B=(1010)2=(10)10

异或运算的性质

  • 满足交换律
    • A A A ^ B B B = B B B ^ A A A
    • 证明: A A A B B B无进位相加等于 B B B A A A无进位相加
  • 满足结合律
    • ( A (A (A ^ B ) B) B) ^ C = C = C= A A A ^ ( B (B (B^ C ) C) C)
    • 证明: A A A B B B无进位相加在和 C C C无进位相加等于 B B B C C C无进位相加在和 A A A无进位相加
  • * 0 0 0 ^ N N N = N = N =N>
    • 证明: 0 0 0 N N N无进位相加结果还是 N N N
  • N N N ^ N N N = 0 0 0
    • 证明: N N N N N N无进位相加结果为 0 0 0

    请理解并记住这里的性质,后面会使用到。

交换两个变量的值(不使用额外变量)

    这是一个经典的面试题,代码如下,请读者先自行理解。

public class Test {// 交换数组中 i 和 j 两个位置的值(注意i != j,如果i == j 那么 arr[i] == arr[j])// 那么经过异或运算(N ^ N = 0)后会把arr[i] arr[j]位置的值刷成0public static void swap(int[] arr,int i,int j) {arr[i] ^= arr[j];arr[j] ^= arr[i];arr[i] ^= arr[j];}public static void main(String[] args) {int a = 3;int b = 5;// swap1a = a ^ b; // ①b = a ^ b; // ②a = a ^ b; // ③System.out.println(a + " " + b);}
}

    为什么跑完①②③就能完成两个变量的交换呢?现在我们将 a a a记作 a 1 a_1 a1,b记作 b 1 b_1 b1,第一步, a = a 1 a = a_1 a=a1 ^ b 1 b_1 b1,第二部, b = ( a 1 b = (a_1 b=(a1 ^ b 1 ) b_1) b1) ^ b 1 = a 1 = a b_1 = a_1 = a b1=a1=a,第三步, a = ( a 1 a = (a_1 a=(a1 ^ b 1 ) b_1) b1)^ a 1 = b 1 a_1 = b_1 a1=b1,在这里进行计算式不要忽视了上一步计算的对 a b a b ab的影响。这样跑完这三行代码之后就玩成了对两个变量的交换。注意:位运算的效率远高于算术运算。

只出现一次的数字

    这是一道leetcode原题,传送门请点我!!!

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

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

    那么怎么考虑这个问题呢?我们前面讲过异或运算满足交换律和结合律那么在这里设这组数为:

n u m s 1 , n u m s 2 , n u m s 3 , . . . . . . n u m s n − 1 nums_1,nums_2,nums_3,...... nums_{n - 1} nums1,nums2,nums3,......numsn1

    假设 n u m s i nums_i numsi 为数组中出现了奇数次的数,我们队这组数调整顺序:

n u m s i , n u m s 1 , n u m s 2 , . . . . . . n u m s i , n u m s i + 1 , . . . . . . n u m s n − 1 nums_i, nums_1 , nums_2, ...... nums_{i}, nums_{i + 1},......nums_{n-1} numsi,nums1,nums2,......numsi,numsi+1,......numsn1

    调整完顺序之后,由于除了 n u m s i nums_i numsi其他数都出现了偶数次那么有:

n u m s i nums_i numsi ^ n u m s 1 nums_1 nums1 ^ n u m s 2 nums_2 nums2 ^ … ^ n u m s n − 1 = n u m s i nums_{n - 1} = nums_i numsn1=numsi ^ 0 = n u m s i 0 = nums_i 0=numsi

    有了上述推导,我们只要将所有数全部都异或到初值为 0 0 0的变量 x o r xor xor中就可以在 O ( N ) O(N) ON的时间复杂度, O ( 1 ) O(1) O(1)的空间复杂度内得到出现了奇数次的数了。

  public static void oddTimesNum(int[] arr) {int xor = 0;for (int num : arr) {// foreach,迭代器实现xor ^= num;}System.out.println(xor);}

只出现一次的数字 III

    这是一道leetcode原题传送门清点我!!!

    给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。你必须设计并实现线性时间复杂度的算法且仅使用常量额外空间来解决此问题。

    我们首先强化一下这个命题,有两个元素出现了奇数次,其他元素都出现了偶数次,找出那两个出现奇数次的数。

    在介绍这道题之前,我们先介绍一种操作,就是提取出一个数二进制中最右侧的1,比如提取出24最右侧的1

// 24
// 11000
// 提取出最右侧的1
// 01000 => 8

    那么怎么完成这个操作呢? a a a & ( a + 1 ) (~a + 1) ( a+1) 就能做到这个操作。

// 就拿a = 24举例
// 	a 	11000				
// ~a 	00111	//~a+1 	01000
//	a		11000	
// & ------------
// 			01000
// 这样就取出了a最右侧的1

    有了上面的铺垫我们就可以继续看这道题目了,我们先将所有数异或到初值为 0 0 0的变量 x o r 1 xor1 xor1

x o r 1 = n u m s 1 xor1 = nums_1 xor1=nums1 ^ n u m s 2 nums_2 nums2 ^ … ^ n u m s n − 1 nums_{n - 1} numsn1

    设这两个奇数为 a a a b b b,那么有:

x o r 1 = a xor1 = a xor1=a ^ b b b

    我们继续分析,我们可以 x o r 1 xor1 xor1中最右侧的1提取出来,由于a ! = b != b !=b所以 x o r 1 xor1 xor1的二进制位中一定会有 1 1 1,比如 x o r 1 xor1 xor1的第 i i i位为 1 1 1。那么这意味这什么?意味着a和b的二进制在第i位上是不一样的,这样我们就可以用这个性质将数组中的数分为两类,一类是第 i i i位是 1 1 1的,一类是第 i i i位是 0 0 0的。我们在准备一个初值为 0 0 0的变量 x o r 2 xor2 xor2将第一类数全部异或上。我们分析下,异或后 x o r 2 xor2 xor2的值。

     x o r 2 = a xor2 = a xor2=a ^ . . . . . . ...... ...... 后面可能有数可能没数,这不影响(因为它们会出现偶数次,异或后值为0)

    我们发现, x o r 2 xor2 xor2的值为 a a a!!!最后我们只需要将 x o r 2 xor2 xor2 x o r 1 xor1 xor1异或就可以得到另一个数 b b b了!!!

  public static void printOddTimesNum2(int[] arr) {// 两种数 一种为 a 一种为 bint xor1 = 0;for (int num : arr) {xor1 ^= num;}// 此时 eor1 = a ^ b;// 数组中所有的数可以分为两类(a != b)// 拿到eor最右侧的1 eor & (~eor + 1) => (eor & (-eor))// 1. 第一类rightOne a 和一些出现了偶数次的数// 2. 第二类NonRightOne b 和一些出现了偶数次的数int rightOne = xor1&(~xor1 + 1);int xor2 = 0;for(int num : arr) {if((num & rightOne) != 0) {xor2 ^= num;}}// 此时eor1就得到了第一类数,再将xor1和xor2进行异或就可以得到第二类数了System.out.println(xor2 + " " + (xor1 ^ xor2));}

只出现一次的数字 II

    这是一道leetcode原题传送门清点我!!!

     给你一个整数数组 nums ,除某个元素仅出现 一次外,其余每个元素都恰出现三次 。请你找出并返回那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。

     同样,我们先强化一下这个命题,数组nums中,某个元素出现了k次,其余每个元素都出现了 m m m次,找到并返回出现了 k k k次的数。那么对于这个问题,我们又该如何取作呢?

    这个问题,我们是这样考虑的,先准备一个长度为32的二进制信息数组t,将nums数组中的所有数的二进制中 1 1 1出现的次数统计到t数组中。由于 k < m k < m k<m所以对于t数组中的每一位,如果t[i]的值是对m取余等于k,说明出现了k次的数的二进制在第 i i i位上是 1 1 1。什么意思,举个例子当 k = 1 m = 3 k = 1 m = 3 k=1m=3 是就是上面这道leetcode原题,给定nums数组[2,2,3,2],我们统计其中所有数的二进制信息得到t数组 [00000000 00000000 00000000 00000041],其中第32位为1对 m m m(3)取模,后等于k,所以出现 k k k次的数在第32位上是1,同理第31位上也是1,最后得到出现 k k k次的数字的二进制0011,从而还原出3出现了 k k k次。

    我们还可以讨论组成第 t [ i ] t[i] t[i]位的数值的情况,可能出现了 k k k次的数在这位上是 1 1 1,可能其他出现了 m m m次的数在这位上也是 1 1 1

①: t [ i ] = k + n × m ( n t[i] = k + n \times m(n t[i]=k+n×m(n个数出现了 m m m次, n = n = n= n u m s . l e n g t h − k m nums.length - k \over m mnums.lengthk),我们可以让 t [ i ] t[i] t[i] 对m取模,如果等于 k k k,则出现了 k k k次的数在第 i i i位上是 1 1 1

②: t [ i ] = k t[i] = k t[i]=k,由于 k < m k < m k<m ,所以对 m m m取模,值还是 k = = k k == k k==k,所以现了 k k k次的数在第i位上是 1 1 1

③: t [ i ] = n × m t[i] = n \times m t[i]=n×m,对 m m m取模后值为 0 0 0,所以现了 k k k次的数在第 i i i位上是 0 0 0

④: t [ i ] = 0 ! = k t[i] = 0 != k t[i]=0!=k,所以现了 k k k次的数在第 i i i位上是 0 0 0

    综上,只要满足 t [ i ] t[i] t[i] % m = = k m == k m==k则出现了看次的数在第i位上是 1 1 1,从而还原出出现了 k k k次的数。

public static int OnlyKTimes(int[] arr, int k, int m) {int[] t = new int[32];for (int x : arr) {// foreachfor (int i = 0; i <= 31; i++) {t[i] += (x >> i) & 1;// ①统计位1}}int ans = 0;for (int i = 0; i <= 31; i++)if (t[i] % m == 0k) {ans |= (1 << i);// ②设置答案}return ans;
}

    这里留下①和②两个点读者可以自行思考。

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

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

相关文章

小程序分享当前页面

小程序分享页面的时候&#xff0c;大部分的资料都是显示的是onShareAppMessage 这个方法 /*** 用户点击右上角分享*/onShareAppMessage(res) {return {title: 您的好友向您分享了一本通讯录: this.data.setting.name,imageUrl: this.data.setting.share_img,path: pages/shar…

GO学习之 互斥锁、读写锁该如何取舍

GO系列 1、GO学习之Hello World 2、GO学习之入门语法 3、GO学习之切片操作 4、GO学习之 Map 操作 5、GO学习之 结构体 操作 6、GO学习之 通道(Channel) 7、GO学习之 多线程(goroutine) 8、GO学习之 函数(Function) 9、GO学习之 接口(Interface) 10、GO学习之 网络通信(Net/Htt…

Postman使用json提取器和正则表达式实现接口的关联

近期在复习Postman的基础知识&#xff0c;在小破站上跟着百里老师系统复习了一遍&#xff0c;也做了一些笔记&#xff0c;希望可以给大家一点点启发。 一&#xff09;使用json提取器实现接口关联 实际项目场景&#xff0c;在财务信息页面&#xff0c;需要上传一个营业执照&…

C++进阶-STL set/multiset容器和map容器的简单认识

set/multiset容器的简单认识 set基本概念set与multiset 的区别&#xff1a;set容器的构造和赋值set容器的大小和交换set容器的插入与删除set容器的查找和统计set容器-set和multiset的区别set容器内置类型指定排序规则set容器自定义数据类型指定排序规则 pair对组创建map容器的基…

【3年轻量】腾讯云2核2G4M和2核4G5M服务器配置优惠价格表

腾讯云轻量应用服务器特价是有新用户限制的&#xff0c;所以阿腾云建议大家选择3年期轻量应用服务器&#xff0c;一劳永逸&#xff0c;免去续费困扰。腾讯云轻量应用服务器3年可以选择2核2G4M和2核4G5M带宽&#xff0c;3年轻量2核2G4M服务器540元&#xff0c;2核4G5M轻量应用服…

ES-java

全文搜索&#xff0c;拆分&#xff0c;分词--获得id&#xff0c;获取部分数据装载进去&#xff0c;简化版数据&#xff0c;用一种状态展示出来&#xff0c;点击详情走的是数据库查询查看显示详情 倒排索引&#xff08;特征&#xff09;&#xff0c;创建文档&#xff0c;使用文…

.net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler

asp.net core IHttpClientFactroy 进行SSL(https)请求时注入ConfigurePrimaryHttpMessageHandler解决https请求错误&#xff1a; static public class CreditScoreServiceExtension{static public void AddCreditScoreQueryServiceHttpClient(this IServiceCollection services…

openEuler 系统使用 Docker Compose 容器化部署 Redis Cluster 集群

openEuler 系统使用 Docker Compose 容器化部署 Redis Cluster 集群 Redis 的多种模式Redis-Alone 单机模式Redis 单机模式的优缺点 Redis 高可用集群模式Redis-Master/Slaver 主从模式Redis-Master/Slaver 哨兵模式哨兵模式监控的原理Redis 节点主客观下线标记Redis 节点主客观…

Vue组件传

跟禹神学vue--总结 1 父组件给子组件传递参数--props传参 &#xff08;1&#xff09;父组件中准备好数据 data() {return {todos:[{id:001,title:01,done:true},{id:002,title:02,done:false},{id:003,title:03,done:true}]} } &#xff08;2&#xff09;父组件中引入子组件…

django建站过程(4)创建文档显示页面

django建站过程&#xff08;4&#xff09;创建文档显示页面 创建文档显示页面项目主文件夹schoolapps中的文件urls.py在APP“baseapps”中创建url.py文件编写视图模板继承bootstrap创建head.html创建doclist.html创建docdetail.html 使用 markdown 编辑器安装模块Model 模型的d…

Azure 机器学习 - 机器学习中的企业安全和治理

目录 限制对资源和操作的访问网络安全性和隔离数据加密数据渗透防护漏洞扫描审核和管理合规性 在本文中&#xff0c;你将了解可用于 Azure 机器学习的安全和治理功能。 如果管理员、DevOps 和 MLOps 想要创建符合公司策略的安全配置&#xff0c;那么这些功能对其十分有用。 通过…

Unity中全局光照GI的总结

文章目录 前言一、在编写Shader时&#xff0c;有一些隐蔽的Bug不会直接报错&#xff0c;我们需要编译一下让它显示出来&#xff0c;方便修改我们选择我们的Shader&#xff0c;点击编译并且展示编译后的Shader后的内容&#xff0c;隐蔽的Bug就会暴露出来了。 二、我们大概回顾一…

acwing算法基础之数学知识--判断质数

目录 1 基础知识2 模板3 工程化 1 基础知识 质数和合数&#xff0c;这两个概念都是针对大于等于2的整数定义的。 质数&#xff1a;大于等于2&#xff0c;并且约数只有1和它本身。比如2、3、5、7等等。 判断质数的方法&#xff1a; 从定义出发&#xff0c;时间复杂度O( n \s…

【Python大数据笔记_day06_Hive】

hive内外表操作 建表语法 create [external] table [if not exists] 表名(字段名 字段类型 , 字段名 字段类型 , ... ) [partitioned by (分区字段名 分区字段类型)] # 分区表固定格式 [clustered by (分桶字段名) into 桶个数 buckets] # 分桶表固定格式 注意: 可以排序[so…

红队系列-IOT安全深入浅出

红队专题 设备安全概述物联网设备层次模型设备通信模型 渗透测试信息收集工具 实战分析漏洞切入点D-link 850L 未授权访问 2017 认证绕过认证绕过 D-link DCS-2530Ltenda 系列 路由器 前台未授权RTSP 服务未授权 访问 弱口令命令注入思科 路由器 固件二进制 漏洞 IoT漏洞-D-Lin…

OpenCV C++ 图像处理实战 ——《多二维码识别》

OpenCV C++ 图像处理实战 ——《多二维码识别》 一、结果演示二、zxing库配置2.1下载编译三、多二维码识别3.1 Method one3.1.1 源码3.2 Method two3.2.1 源码四、源码测试图像下载总结一、结果演示 </

国际阿里云、腾讯云.AWS:新加坡服务器数据中心怎么保护网络安全原创

新加坡服务器数据中心怎么保护网络安全原创 保护新加坡服务器数据中心的网络安全是一个重要的任务&#xff0c;以下是一些常见的保护网络安全的办法和办法&#xff1a; 防火墙设置&#xff1a;装备和办理强壮的防火墙来监控和过滤网络流量&#xff0c;阻止未经授权的拜访和歹意…

12.使用若依异步的功能

引言 在软件开发中&#xff0c;经常会遇到耗时操作&#xff0c;有时候耗时操作会对主逻辑的运行时间有影响&#xff0c;但是耗时的操作又不需要实时反馈&#xff0c;就可以使用异步操作。比如日志的记录&#xff0c;启动程序时&#xff0c;也可以降一下启动时候的耗时操作&…

ES6学习

let和const命名 let基本用法-块级作用域 在es6中可以使用let声明变量&#xff0c;用法类似于var ⚠️ let声明的变量&#xff0c;只在let命令所在的代码块内有效 {let a 10;var b 20; } console.log(a); //a is not defined console.log(b); //20不存在变量提升 var命令…

部署ChatGLM3对话预训练模型

ChatGLM3是智谱AI和清华大学KEG实验室联合发布的新一代对话预训练模型。ChatGLM3-6B是ChatGLM3系列中的开源模型&#xff0c;在保留了前两代模型对话流畅、部署门槛低等众多优秀特性的基础上&#xff0c;ChatGLM3-6B引入了如下特性&#xff1a; 更强大的基础模型&#xff1a;C…