异或运算在面试题中的应用

news2025/4/22 3:41:01

异或运算 是 涉及到数据位运算时常见的处理方式。如何进行异或运算?在对应位上,相同为0,不同1,但其实两个数据异或运算就是进行无进位加法

例如: int a = 7, b = 6,  a ^b = ?

算法1: 相同为0,不同为1

                     

                                                            a ^ b=  :     0         0         0         1

算法2: 无进位相加

                    

                                                             a ^ b=  :     0         0         0         1

异或运算的性质

1)0^N == N  

2)  N^N == 0

3)  异或运算满足交换律和结合律  

       交换律: a^b = b^a

       结合律:a^b^c = a^(b^c)

题目1:如何不用额外变量交换两个数?

//代码段1

#include <stdio.h>

void swap(int* a, int i, int j){
    a[i] = a[i]^a[j];
    a[j] = a[i]^a[j];
    a[i] = a[i]^a[j];
}

int main(){
    
    return 0;
}

代码解析:

为什么执行了 a = a^b; b = a^b; a= a^ b; 这三句代码,a和b的值就被交换了?

设:变量 a = A, b = B;

a = a ^ b;   \Rightarrow a = A^B,  b = B;

b = a ^ b;   \Rightarrow b = B^A^B,  由于异或运算满足交换律,所以,b = B^B^A , 又因为N^N == 0 且 0^N = N, 所以,b = A;

a = a ^ b;   \Rightarrow a = A^B^A = B

Tip:

        如果使用异或运算交换数据 a 和 b的值, a 和 b的值 可以相等,但是二者必须指向不同的内存空间,不能是同一个变量。例如在代码段1中,交换数组a[i] 和a[j] 的值 ,  a[i] 可以等于 a[j] (a[i] == a[j] == X),但是 i 不可以等于j,因为,如果 i== j , a[i] ^ a[j]  \Rightarrow a[i]  ^ a[i]  , 根据异或运算的性质,一个数与其自身进行异或运算,结果为0(N^N=== 0). 所以 如果 i 等于 j ,执行了swap函数后,a[i]  和 a[j] 都将被置0.

题目2:一个数组中有一种数出现了奇数次,其他数都出现了偶数次,找到并打印这种出现了奇数次的数。

题目解析:

这道题同样是异或运算的性质的应用:N^N == 0 和 0^N == N 

两个N异或等于0,那么n个N异或呢?即 N^N^N...^N = ? 结果显而易见,如果n为偶数,那么结果就是0,如果是n为奇数,那么这个连续异或的式子就最终简化为 0 ^N , 继续利用异或的性质,这个结果为N。

综上分析,如果把这个数组中的数据依次执行异或运算, 假设数组名为a, 那么

a[0]^ a[1] ^ a[2] ^ ... a[n]  最终结果就是 0 ^ a[i] , a[i] 即为出现了奇数次的那个元素。

代码实现:

//代码段2

#include <stdio.h>

int findOdd(int* a , int n){
    int eor = 0;
    for(int i = 0;i < n;i++){
        eor ^= a[i];
    }
    return eor;
}
int mian(){

    int a[11] = {1,1,1,1,2,2,3,3,3,3,3};
    printf("odd is %d\n",findOdd(a,11));
    return 0;
}

 运行结果:

 题目3:如何把一个int类型的数,提取出最右侧的1?

题目解析

题目要求将一个int类型的数的最右侧的1提取出来,那么必然涉及将int型数的二进制表达及相关位运算。例如:int a = 0110 1110 0100 0000, 根据题目要求,要找到它最右侧的1,那么得到的结果应该是 ans = 0000 0000 0100 0000 ,对其它数位的情况并不关心。

如何通过 a 得到结果ans 呢? 即  a \to ans  需要经过怎样的运算? ans = a & (~a +1)

因为ans 要求除了a的最右侧的1保留,其它位上都为0, 而一个数与它的相反数做“与”操作,结果就是0,但是最右侧的1被保留,就说明除了最右侧1这一位,其它位都是与其相反数做了“与”操作,因此 (~a+1)就是使a的最右侧1这一位在与反后,又被置成了1.

                            a =  0110 1110 0100 0000

                          ~a = 1001 0001 1011 1111

                      ~a+1 = 1001 0001 1100 0000

             a & (~a+1) = 0000 0000 0100 0000

 代码实现:

//代码段3
#include <stdio.h>

int findRight_1(int a){
    return a & (~a+1)
}

另:(~a+1 )其实就是-a , 代码段3可以写成代码段4,结果是一样的。

//代码段4
#include <stdio.h>

int findRight_1(int a){
    return a & (-a)
}

题目4: 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数?

题目解析:

经过题目2的分析,我们知道如果将这个数组从头到尾的异或一遍,出现了偶数次的数被销掉了,结果为 eor = a ^ b , a 和 b是出现了奇数次的两种数,因为题目明确说了出现奇数次的是两种数,那么 a 不等于 b,所以 eor就不等于0。从左往右依次查看eor每一个bit位,肯定有一个bit位是1,假设是第i位 , 进一步假设a 的第i位是1, b的第 i 位是 0 。那么,原数组就可以分成两类,第一类为第i位是1的数,第二类为第i位是0的数。

第一类:数组中第 i 位 是 1的数第二类: 数组中第 i 位是 0 的数
ab
出现了偶数次且 第 i 位是 1的数出现了偶数次且 第 i 位是 0的数

如果将第一类中的数,从头到尾执行一遍异或运算,会发生什么?"出现了偶数次且第i位为1的数” 依然化为零被销掉了,结果是  {eor}' = a 

同理,将第二类中的数,从头到尾执行一遍异或运算,“出现了偶数次且第 i 位为0 的数” 被销掉,结果 {eor}'' = b.  但是,在求b时 可以利用eor的结果: {eor}'' = eor ^ {eor}' 

难点:

1. 将数组从头到尾执行一遍异或运算 ,结果为 eor 

1. 找到eor 结果中最右端第一个1 的bit 位 :bit_i .  (这个问题就可以利用题目3 的思路)

2. 遍历数组,找到bit_i 位上都为1 的数据,并保存到数组B;

3 将数组B 从头到尾执行一遍异或运算,结果{eor}' 就是其中一个奇数次 数;

{eor}'' = {eor}' ^ eor , 得到另一个奇数次数

代码实现

#include <stdio.h>

/* arr :  待处理数组
   n:arr长度
   a:出现奇数次的数据1
   b:出现奇数次的数据2
*/
void findOdd_2(int* arr, int n, int* a, int* b){
    int eor = 0;
    for(int i = 0;i < n;i++){
        eor ^= arr[i];
    }
  
    int bit_1 = eor & (-eor); //提取最右侧的1
 
    int eor_a = 0;
 
    for(int i = 0;i < n;i++){
       if(arr[i] & bit_1){
           eor_a ^= arr[i];
       }
    }

    *a = eor_a;
    *b = eor_a ^ eor;
}
 
int main(){
    int arr[16] = {12,12,12,19,19,19,13,13,13,13,45,45,66,66,66,66};
    int a = 0, b = 0;
    findOdd_2(arr,16,&a,&b);
    printf("a = %d, b = %d\n",a,b);
    return 0;
 }

运行结果:

题目5: 一个数组中有一种数出现K次,其他数都出现了M次,M>1, K<M, 请找到出现了K次的数,要求额外空间复杂度为O(1) ?

题目解析:

首先利用一个实例来进一步解释题目:假设数组A中共有4种数,a, b ,c ,d, 其中,a 出现了k次,b、c 和d 都出现了M次, M>1, k<M.

题目5与题目4很相似,都是根据元素在数组中出现的次数来确定元素值,但是题目5中并未明确数据出现次数的具体值。一个整型数是32个bit位,定义一个大小为32 的数组 int  arr[32] ,  arr[i] 表示原数组中 第i位为1 的数据元素的总和,例如,数组A中:

a的第i位 为1,b的第i位为1,c 和 d 的第i位为0,则 arr[i] = 1*K+ 1*M +0+0 = k+M;

a的第i+1 位1,b的第i+1位位1, c 的第i+1位为1, d的第i+1位为0, 则 arr[i+1] = K+M+M+0 = k+2M;

以此类推,计算出arr中 0~31 个元素的值。

再逆向思考,如果 arr[i] % M == 0 ,说明数组A中只有出现M次的元素在arr[i] 上是1;arr[i] % M !=  0, 说明数组A中出现K次的元素在arr[i] 为1. 

代码实现:

#include <stdio.h>

int findK(int* arr, int n, int k, int M){
    int bit32[32] = {0};
    for(int i = 0;i < n;i++){  //遍历数组arr中的每个元素
        for(int j = 0; j < 32;j++){ //遍历arr[i] 的32个bit位
            bit32[j] += (arr[i]>>j) & 1; //如果arr[i]的第j个bit位为1,则bit[j] 加1;
        }
    }
    int ans = 0; //出现k次的数据
    for(int i = 0;i < 32;i++){ //遍历数组bit32
        if(bit32[i] % M){ //如果bit[i]% M 不为0,说明在出现K次的数据在第i个bit位上是1
            ans += 1 << i; //将出现k次数据的第i个bit位置为1
        }  
    }
    return ans; 
}

总结:对异或运算的考察,主要是对其性质的考察,在实际问题中能够灵活的运用其性质。 上述题目5虽然没有使用异或运算,但是给我们提供了一种利用位运算解决问题的思路。

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

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

相关文章

和鲸科技携手浙江大学地球科学学院,助推地球科学研究范式变革

近日&#xff0c;浙江省资源与环境信息系统重点实验室&#xff08;下简称“实验室&#xff09;与上海和今信息科技有限公司&#xff08;下简称“和鲸科技”&#xff09;签订合作框架协议&#xff0c;双方将以助推“数据算力模型科研场景”的地球科学研究范式变革&#xff0c;孕…

BFD(简单配置实验)

实验拓扑 配置接口IP地址 正常互通 配置静态BFD 查看状态&#xff1a;为UP 与静态路由联动 查看静态路由状态为active 将交换机的接口down掉 BFD的状态为down 再次查看静态路由的状态为Inactive

阿里云运维第一步(监控):开箱即用的监控

作者&#xff1a;仲阳 这是云的时代&#xff0c;现在云计算已经在各行各业广泛的应用。但是上云对于大多数客户来说&#xff0c;依然有很大的学习成本&#xff0c;如下图仅是阿里云都有几百款产品&#xff0c;怎么选择&#xff1f;怎么用&#xff1f;对于客户来说都是问题。“…

后端常见问题解答-位运算实际场景讲解

位运算 在计算机存储的世界中&#xff0c;一切都是二进制的&#xff0c;位运算就是对二进制位进行操作的一种运算。位运算是计算机中的一种常见运算&#xff0c;可以用来提高性能和提升代码的可读性。 位运算有很多种&#xff0c;比如与、或、非、异或等&#xff0c;这些运算…

【踩坑】解决运行一段时间GPU计算后忽然变得很慢

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 发现问题 问题分析 修复思路 思路一 思路二 思路二对应代码 这个问题真的找了我好久&#xff0c;但说起来其实也简单&#xff0c;就是GPU温…

XILINX 7系列XDMA使用_IP核介绍以及工程搭建

文章目录 一、XDMA IP核1.1、接口说明1.2、配置页说明 二、XDMA工程搭建2.1、BD搭建2.2 Linux下XDMA驱动安装2.3 Linux下使用XDMA进行数据传输 一、XDMA IP核 1.1、接口说明 sys_clk&#xff1a;主机给PCIE提供的时钟信号&#xff0c;通过原理图查看 sys_rst_n&#xff1a;主机…

Flowable工作流中会签节点处理回退并清除审批意见

文章目录 1&#xff0c;操作方法及步骤2&#xff0c;实现细节3&#xff0c;总结 1&#xff0c;操作方法及步骤 在Flowable工作流会签流程中&#xff0c;如果最后一个人选择回退流程&#xff0c;想要清除前面用户A和B填写的审批意见&#xff0c;需要通过Flowable提供的API来操作…

LVS_Director + KeepAlived + 邮件报警

目录 一. 环境准备 二. 对master和backup操作 三. 配置master主机 四. 配置backup主机 六. 验证虚拟IP 七. 配置后端两个web服务器 对web1和web2主机都进行如下操作&#xff1a; 单独修改web1主机 单独修改web2主机 验证 八. 设置邮件报警 一. 环境准备 KeepAlive…

【CT】LeetCode手撕—102. 二叉树的层序遍历

目录 题目1-思路2- 实现⭐102. 二叉树的层序遍历——题解思路 3- ACM实现3-1 二叉树构造3-2 整体实现 题目 原题连接&#xff1a;102. 二叉树的层序遍历 1-思路 1.借助队列 Queue &#xff0c;每次利用 ①while 循环遍历当前层结点&#xff0c;②将当前层结点的下层结点放入 …

[大模型]Qwen2-7B-Instruct 接入 LangChain 搭建知识库助手

环境准备 在 autodl 平台中租赁一个 3090 等 24G 显存的显卡机器&#xff0c;如下图所示镜像选择 PyTorch–>2.1.0–>3.10(ubuntu20.04)–>12.1 接下来打开刚刚租用服务器的 JupyterLab&#xff0c;并且打开其中的终端开始环境配置、模型下载和运行 demo。 pip 换源…

图文RAG组件:360LayoutAnalysis中文论文及研报图像分析

AI应用开发相关目录 本专栏包括AI应用开发相关内容分享&#xff0c;包括不限于AI算法部署实施细节、AI应用后端分析服务相关概念及开发技巧、AI应用后端应用服务相关概念及开发技巧、AI应用前端实现路径及开发技巧 适用于具备一定算法及Python使用基础的人群 AI应用开发流程概…

ripro主题如何使用memcached来加速

ripro主题是个很不错的资源付费下载主题。主题自带了缓存加速开关&#xff0c;只要开启了缓存加速功能&#xff0c;正常情况下能让网站访问的速度提升很大。 但好多人这么做了却发现没啥加速效果&#xff0c;原因就在于wordpress里缺少了memcache文件。只需要把object-cache.ph…

电脑怎么录制游戏视频?轻松捕捉每一帧精彩

随着游戏产业的蓬勃发展&#xff0c;越来越多的玩家不仅满足于在游戏世界中的探索与冒险&#xff0c;更希望将自己的游戏精彩瞬间记录下来&#xff0c;分享给更多的朋友。可是电脑怎么录制游戏视频呢&#xff1f;本文旨在为广大游戏爱好者提供一份详细的电脑游戏视频录制攻略&a…

MySQL员工练习

MySQL员工练习 1.数据显示 员工信息表emp&#xff1a; 字段&#xff1a;员工id,员工名字,工作岗位,部门经理,受雇日期,薪水,奖金,部门编号 英文名&#xff1a;EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,BONUS,DEPTNO 部门信息表dept&#xff1a; 字段&#xff1a;部门编号,部门名称,部…

vscode 终端无法正常执行脚本命令如何解决

我们经常需要在vscode的中安装第三方依赖包&#xff0c;npm是前端目前最大的Node.js模块化管理系统&#xff0c;它能帮助开发者管理和发布Node.js模块。但很多时候我们在vscode的终端中执行npm install命令时经常会报以下错误&#xff1a; 但是在Windows的cmd命令提示符中执行n…

VM映像构建实践

概述 VM映像做为创建VM的必要条件&#xff0c;各类云环境映像市场均有提供最基础的映像。创建VM后&#xff0c;通常还需要根据组织或用户的需求&#xff0c;安装一些软件、修改配置后才能满足使用需求。这类需求通常可以手动部署或者借助一些配置管理工具&#xff0c;如ansibl…

KVM+GFS分布式存储系统构建高可用群集

KVMGFS 分布式存储系统构建 KVM 高可用群集 一&#xff1a;理论概述 1.1&#xff1a;Glusterfs 简介 Glusterfs 文件系统是由 Gluster 公司的创始人兼首席技术官 Anand Babu Periasamy编写。 一个可扩展的分布式文件系统&#xff0c; 用于大型的、 分布式的、 对大量数据进行访…

Java版SaaS模式云HIS系统源码Java+Spring+SpringBoot+SpringMVC 基层卫生健康云HIS源码

Java版SaaS模式云HIS系统源码JavaSpring&#xff0b;SpringBoot&#xff0b;SpringMVC 基层卫生健康云HIS源码 云HIS全称为基于云计算的医疗卫生信息系统&#xff08;Cloud-BasedHealthcareInformationSystem&#xff09;&#xff0c;是运用云计算、大数据、物联网等新兴信息技…

宝藏速成秘籍(6)归并排序法

一、前言 1.1、概念 归并排序&#xff08;Merge Sort&#xff09;是一种基于分治思想的排序算法。它将数组分成两个子数组&#xff0c;分别对这两个子数组进行排序&#xff0c;然后再将它们合并成一个有序的数组。归并排序是一种经典的分治算法&#xff0c;它的核心思想是将待…