异或思想的算法题

news/2025/1/18 7:26:08/

异或思想的算法

1.消失的数字

题目链接

数组nums包含从0n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?

示例 1:

输入:[3,0,1]
输出:2

示例 2:

输入:[9,6,4,2,3,5,7,0,1]
输出:8

采用异或的思想

我们知道 异或的规则是相同为0 不同为1 , 我们让一个数字去和0~numsize之间的数去异或,再让它去跟数组里的值去异或,由于消失的数字只会出现一次,其他数字会出现两次,而出现两次数字对应的二进制位的1 终究会被抵消,因此最后二进制位留下来的1 和 0 就是消失的那个数字的二进制位

image-20240429155457762

代码如下:

int missingNumber(int* nums, int numsSize)
{// 让missing 一开始等于这个数组的元素个数int missing = numsSize;// 创建循环去异或 0~numSize之间的每一个数// 再让其去去异或数组中的每一个数for(int i = 0; i<numsSize; i++){missing ^= i;missing ^= nums[i];}// 走到这里就说明,missing中存储的二进制数就是消失的数字的二进制数return missing;
}

首先,在代码中, missing 初始化为 numsSize,因为我们预设缺失的数字是 numsSize

然后,遍历数组,对于每个索引 i,我们使用异或操作:

  • 第一步,我们将当前遍历到的索引值 i 与 missing 进行异或操作。这会使 missing 中存储的值减少或增加 i,取决于当前遍历到的位置。
  • 第二步,我们将当前位置 i 对应的 nums[i] 与 missing 进行异或操作。由于数组中所有正常的数都会在某个时刻出现两次(一次作为索引,一次作为元素),而那个缺失的数只会被用一次,因此在经历了全部异或操作后,那个缺失的整数就会留在 missing 变量中。

通过以上过程和异或运算的特性,最终得到的 missing 即为缺失的整数值。

我们来看一个难度更高的题目:

2.数组中有两个数字只出现了一次

题目:

只出现一次的数字 III

给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

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

示例 1:

输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。

示例 2:

输入:nums = [-1,0]
输出:[-1,0]

示例 3:

输入:nums = [0,1]
输出:[1,0]

分析:

image-20240429162432557

如图所示:

  1. 我们首先让 ret = 0 去异或所有数组里的数,那么出现两次的数就会被抵消
  2. 因此ret的结果就是两个出现一次的数异或的值
  3. 那我们就要想办法把这两个数给分离出来
  4. 那么我们采取去找到ret中 的 1 也就是二进制中 为 1 的地方,因为如果是1就说明两个只出现一次的数的二进制 在这个位上面 一个为0 一个为1
  5. image-20240502165912592
  6. 如上图所示,ret中第M位为1的,就说明x1,x2两个数的第M位一个是1,一个是0
  7. 接下来我们就去数组中分离出x1和x2
  8. 让第M位为1的为一组。第M位为0的为一组,就说明x1和x2在不同的一组中
  9. image-20240502170224456
  10. 那我们就让ret的每一个位都去&上一个1 如果结果是1 就说明ret的该位就是1,那我们就跳出循环。1<<m的意思是让1左移m个位

image-20240502171159516

  1. 当我们找到了为1的位了,我们就要分离。

    image-20240502172531981

  2. 上图我们让数组的每一个数进行分离,第M位为1 的数就让x1去异或,第M位是0的就让x2去异或,x1异或完全部的数,第M位为1且出现两次的都会抵消,最后剩下的就是只出现一次且第M位为1的数。x2也是同理,第M位为0的数且出现两次的数会被抵消,最后剩下的x2的值就是只出现一次且第M位为0的数

  3. 有一个需要注意的点,我们需要将(1<<m)改成((unsigned int)1 << m),因为int是有符号类型,最高位32位是符号位,不能比较,但是如果传入的数用到了32位,那么我们的程序就无法完成功能的实现。

代码实现:

int* singleNumber(int* nums, int numsSize, int* returnSize) 
{// 我们要让ret去异或数组中所有的数int ret = 0; // 遍历数组for(int i = 0; i < numsSize;i++){ret ^= nums[i];}// 此时的ret是只出现一次的两个数异或的结果// 我们要去检测第m位出现1  要找到这个m  这样我们后面才能对两个数进行分离// 为什么要检测第m位出现1呢,因为如果异或的结果是1 就说明这两个数在这个位上面,一个是1 一个是0// 这个不同点就是我们的突破口int m = 0;while(m < 32) // 32是因为一个int类型是4个字节 32个比特位{// 为什么要让1强制转化成unsigned int类型呢?// int 是有符号类型,最高位(第32为)为符号位,不能比较最高位// 若我们只比较前31位 就会导致一部分int类型无法被我们的程序正确运行if(ret & ((unsigned int)1<<m)) // 1<<m 就是让1左移m个位break; // 如果走进这个循环就说明 第m位就是1 elsem++; // 如果走到这里说明第m位不是1  让m++ 让1继续左移}// 找到了1 之后就要对原数组里的数进行分离// 第m位为1 的数 一组  因为只出现一次的数的其中一个数的第m位也是1 // 第m位为0的数  一组 ,因为另外一个只出现一次的数 的第m位是0int x1 = 0, x2 = 0;for(int i = 0; i < numsSize; i++){// 为什么要让1强制转化成unsigned int类型呢?// int 是有符号类型,最高位(第32为)为符号位,不能比较最高位if(nums[i] & ((unsigned int)1<<m)) // 判断数组下标为i的元素的第m位是否为1{x1 ^= nums[i]; // 让第m位为1的数全部异或,出现两次的数抵消,剩下的就是只出现一次的并且第m位是1的数}else{x2 ^= nums[i];//让第m位为0的数全部异或,出现两次的数抵消,x2最后剩下的就是只出现一次且第m位是0的数}  }// 走到这里x1 和x2 就是我们要的只出现一次的数  int* retArr = (int*)malloc(sizeof(int) * 2);retArr[0] = x1;retArr[1] = x2;*returnSize = 2;return retArr;
}

http://www.ppmy.cn/news/1458672.html

相关文章

c语言循环题目

c语言循环题目 已知sinx的近似计算公式如下sin xx- x3/3! x’/5!-x7/7!.(-1)n-1x2n-1/(2n-1)!其中x为弧度&#xff0c;n为正整数。编写程序根据用户输入的x和n的值&#xff0c;利用上述近似计算公式计算sinx的近似值&#xff0c;要求输出结果小数点后保留8位 int main() {in…

面试:CopyOnWriteArrayList

问题&#xff1a; ArrayList 是线程不安全的&#xff0c;同一时间写和读会造成线程不安全&#xff0c;怎么解决呢&#xff1f; 答&#xff1a;可以使用CopyOnWriteList。 CopyOnWriteList特点 CopyOnWriteArrayList是Java中的一种并发集合类&#xff0c;它实现了List接口&am…

【Linux系统编程】第十二弹---编辑器gcc/g++使用

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、什么是gcc/g 2、gcc/g编辑器的安装 3、gcc/g编译的四个步骤 2.1、预处理 2.2、编译 2.3、汇编 2.4、链接 4、函数库 …

【PyTorch】7-生态简介

PyTorch&#xff1a;7-生态简介 注&#xff1a;所有资料来源且归属于thorough-pytorch(https://datawhalechina.github.io/thorough-pytorch/)&#xff0c;下文仅为学习记录 7.1&#xff1a;torchvision 7.1.1&#xff1a;简介 The torchvision package consists of popula…

第VI章-Ⅰ Vue3生命周期探讨

第VI章-Ⅰ Vue3生命周期探讨 简介Vue3生命周期概览生命周期钩子在选项式 API 中的使用错误捕获钩子 onErrorCaptured 生命周期钩子在组合式 API 中的使用错误捕获钩子 onErrorCaptured 总结 简介 在 Vue 3 中&#xff0c;生命周期钩子定义了组件在其创建、挂载、更新和销毁等过…

Linux学习笔记(3)---- Debian测试网速指令及查看是否千兆网卡

测试网速指令 在Debian系统中&#xff0c;测网速的指令主要有以下几种方法&#xff1a; 使用speedtest-cli工具&#xff1a; speedtest-cli是一个常用的网络速度测试工具&#xff0c;可以通过命令行进行安装和运行。首先&#xff0c;需要安装speedtest-cli&#xff1a; sud…

FANUC机器人故障诊断—报警代码(五)

FANUC机器人故障诊断中关于报警代码的介绍更新如下&#xff1a; 一、报警代码&#xff08;SRVO-214&#xff09; SRVO-214 6轴放大器保险丝熔断 [原因]6轴伺服放大器上的保险丝(FS2,FS3)已熔断。括号内的数字表示在第几台6轴伺服放大器上检测出了保险丝熔断。 [对策] 1.保险…

计算机组成原理网课笔记

无符号整数的表示与运算 带符号整数的表示与运算 原反补码的特性对比 移码 定点小数